
import com.epicbot.client.Client;
import com.epicbot.client.game.InteractableManager;
import com.epicbot.client.vf.interactable_manager;
import com.epicbot.event.events.MessageEvent;
import com.epicbot.event.listeners.MessageListener;
import com.epicbot.event.listeners.PaintListener;
import com.epicbot.script.Script;
import com.epicbot.script.ScriptManifest;
import com.epicbot.script.methods.Game;
import com.epicbot.script.methods.Inventory;
import com.epicbot.script.methods.Objects;
import com.epicbot.script.util.Filter;
import com.epicbot.script.wrappers.*;
import com.sun.jna.WString;
import java.awt.*;
import java.lang.reflect.Field;
import java.util.*;

/*
 * To change this template, choose Tools | Templates and open the template in
 * the editor.
 */
/**
 *
 * @author Gregor
 */
@ScriptManifest(authors = {"Nullpointer"}, name = "Dungeoneer", version = 1.0, description = "<html>Settings in GUI<br></html>")
public class Dungeoneer extends Script implements PaintListener, MessageListener {

    public int overallIndex = 0;
    public float playerX = 0;
    public float playerY = 0;
    public Room prevRoom = null;
    public Puzzle puzzle = null;
    public long puzzleStart = 0;
    public HashMap<PathIdentifier, Room[]> paths = new HashMap<PathIdentifier, Room[]>();
    public Integer[] expensiveItemsInteger = {15753, 15755, 15757, 15759, 15761, 15763, 15765, 15767, 15769, 15771, 15773, 16273, 16275, 16277, 16279, 16281, 16283, 16285, 16287, 16289, 16291, 16293, 16297, 16299, 16301, 16303, 16305, 16307, 16309, 16311, 16313, 16315, 16317, 16319, 16321, 16323, 16325, 16327, 16329, 16331, 16333, 16335, 16337, 16339, 16341, 16343, 16345, 16347, 16349, 16351, 16353, 16355, 16357, 16359, 16363, 16365, 16367, 16369, 16371, 16373, 16375, 16377, 16379, 16381, 16383, 16385, 16387, 16389, 16391, 16393, 16395, 16397, 16399, 16401, 16403, 16405, 16407, 16409, 16411, 16413, 16415, 16417, 16419, 16421, 16423, 16425, 16427, 16432, 16437, 16442, 16447, 16452, 16457, 16462, 16467, 16472, 16477, 16482, 16487, 16492, 16497, 16502, 16507, 16512, 16517, 16522, 16527, 16532, 16537, 16542, 16547, 16552, 16557, 16562, 16567, 16572, 16577, 16582, 16587, 16592, 16597, 16602, 16607, 16612, 16617, 16622, 16627, 16632, 16637, 16642, 16647, 16649, 16651, 16653, 16655, 16657, 16659, 16661, 16663, 16665, 16667, 16669, 16671, 16673, 16675, 16677, 16679, 16681, 16683, 16685, 16687, 16689, 16691, 16693, 16695, 16697, 16699, 16701, 16703, 16705, 16707, 16709, 16711, 16713, 16715, 16717, 16719, 16721, 16723, 16725, 16727, 16729, 16731, 16733, 16735, 16737, 16739, 16741, 16743, 16745, 16747, 16749, 16751, 16753, 16755, 16757, 16759, 16761, 16763, 16765, 16767, 16769, 16771, 16773, 16775, 16777, 16779, 16781, 16783, 16785, 16787, 16789, 16791, 16793, 16795, 16797, 16799, 16801, 16803, 16805, 16807, 16809, 16811, 16813, 16815, 16817, 16819, 16821, 16823, 16825, 16827, 16829, 16831, 16833, 16835, 16837, 16839, 16841, 16843, 16845, 16847, 16849, 16851, 16853, 16855, 16857, 16859, 16861, 16863, 16865, 16867, 16869, 16871, 16873, 16875, 16877, 16879, 16881, 16883, 16885, 16887, 16889, 16891, 16893, 16895, 16897, 16899, 16901, 16903, 16905, 16907, 16909, 16911, 16913, 16915, 16917, 16919, 16921, 16923, 16925, 16927, 16929, 16931, 16933, 16935, 16937, 16939, 16941, 16943, 16945, 16947, 16949, 16951, 16953, 16955, 16957, 16959, 16961, 16963, 16965, 16967, 16969, 16971, 16973, 16975, 16977, 16979, 16981, 16983, 16985, 16987, 16989, 16991, 16993, 16995, 16997, 16999, 17001, 17003, 17005, 17007, 17009, 17011, 17013, 17015, 17017, 17019, 17021, 17023, 17025, 17027, 17029, 17031, 17033, 17035, 17037, 17039, 17041, 17043, 17045, 17047, 17049, 17051, 17053, 17055, 17057, 17059, 17061, 17063, 17065, 17067, 17069, 17071, 17073, 17075, 17077, 17079, 17081, 17083, 17085, 17087, 17089, 17091, 17093, 17095, 17097, 17099, 17101, 17103, 17105, 17107, 17109, 17111, 17113, 17115, 17117, 17119, 17121, 17123, 17125, 17127, 17129, 17131, 17133, 17135, 17137, 17139, 17141, 17143, 17145, 17147, 17149, 17151, 17153, 17155, 17157, 17159, 17161, 17163, 17165, 17167, 17169, 17171, 17173, 17175, 17177, 17179, 17181, 17183, 17185, 17187, 17189, 17191, 17193, 17195, 17197, 17199, 17201, 17203, 17205, 17207, 17209, 17211, 17213, 17215, 17217, 17219, 17221, 17223, 17225, 17227, 17229, 17231, 17233, 17235, 17237, 17239, 17241, 17243, 17245, 17247, 17249, 17251, 17253, 17255, 17257, 17259, 17261, 17263, 17265, 17267, 17269, 17271, 17273, 17275, 17277, 17279, 17281, 17283, 17285, 17287, 17289, 17291, 17293, 17295, 17297, 17299, 17301, 17303, 17305, 17307, 17309, 17311, 17313, 17315, 17317, 17319, 17321, 17323, 17325, 17327, 17329, 17331, 17333, 17335, 17337, 17339, 17341, 17343, 17345, 17347, 17349, 17351, 17353, 17355, 17357, 17359, 17361};
    public int[] expensiveItemsInt = {15753, 15755, 15757, 15759, 15761, 15763, 15765, 15767, 15769, 15771, 15773, 16273, 16275, 16277, 16279, 16281, 16283, 16285, 16287, 16289, 16291, 16293, 16297, 16299, 16301, 16303, 16305, 16307, 16309, 16311, 16313, 16315, 16317, 16319, 16321, 16323, 16325, 16327, 16329, 16331, 16333, 16335, 16337, 16339, 16341, 16343, 16345, 16347, 16349, 16351, 16353, 16355, 16357, 16359, 16363, 16365, 16367, 16369, 16371, 16373, 16375, 16377, 16379, 16381, 16383, 16385, 16387, 16389, 16391, 16393, 16395, 16397, 16399, 16401, 16403, 16405, 16407, 16409, 16411, 16413, 16415, 16417, 16419, 16421, 16423, 16425, 16427, 16432, 16437, 16442, 16447, 16452, 16457, 16462, 16467, 16472, 16477, 16482, 16487, 16492, 16497, 16502, 16507, 16512, 16517, 16522, 16527, 16532, 16537, 16542, 16547, 16552, 16557, 16562, 16567, 16572, 16577, 16582, 16587, 16592, 16597, 16602, 16607, 16612, 16617, 16622, 16627, 16632, 16637, 16642, 16647, 16649, 16651, 16653, 16655, 16657, 16659, 16661, 16663, 16665, 16667, 16669, 16671, 16673, 16675, 16677, 16679, 16681, 16683, 16685, 16687, 16689, 16691, 16693, 16695, 16697, 16699, 16701, 16703, 16705, 16707, 16709, 16711, 16713, 16715, 16717, 16719, 16721, 16723, 16725, 16727, 16729, 16731, 16733, 16735, 16737, 16739, 16741, 16743, 16745, 16747, 16749, 16751, 16753, 16755, 16757, 16759, 16761, 16763, 16765, 16767, 16769, 16771, 16773, 16775, 16777, 16779, 16781, 16783, 16785, 16787, 16789, 16791, 16793, 16795, 16797, 16799, 16801, 16803, 16805, 16807, 16809, 16811, 16813, 16815, 16817, 16819, 16821, 16823, 16825, 16827, 16829, 16831, 16833, 16835, 16837, 16839, 16841, 16843, 16845, 16847, 16849, 16851, 16853, 16855, 16857, 16859, 16861, 16863, 16865, 16867, 16869, 16871, 16873, 16875, 16877, 16879, 16881, 16883, 16885, 16887, 16889, 16891, 16893, 16895, 16897, 16899, 16901, 16903, 16905, 16907, 16909, 16911, 16913, 16915, 16917, 16919, 16921, 16923, 16925, 16927, 16929, 16931, 16933, 16935, 16937, 16939, 16941, 16943, 16945, 16947, 16949, 16951, 16953, 16955, 16957, 16959, 16961, 16963, 16965, 16967, 16969, 16971, 16973, 16975, 16977, 16979, 16981, 16983, 16985, 16987, 16989, 16991, 16993, 16995, 16997, 16999, 17001, 17003, 17005, 17007, 17009, 17011, 17013, 17015, 17017, 17019, 17021, 17023, 17025, 17027, 17029, 17031, 17033, 17035, 17037, 17039, 17041, 17043, 17045, 17047, 17049, 17051, 17053, 17055, 17057, 17059, 17061, 17063, 17065, 17067, 17069, 17071, 17073, 17075, 17077, 17079, 17081, 17083, 17085, 17087, 17089, 17091, 17093, 17095, 17097, 17099, 17101, 17103, 17105, 17107, 17109, 17111, 17113, 17115, 17117, 17119, 17121, 17123, 17125, 17127, 17129, 17131, 17133, 17135, 17137, 17139, 17141, 17143, 17145, 17147, 17149, 17151, 17153, 17155, 17157, 17159, 17161, 17163, 17165, 17167, 17169, 17171, 17173, 17175, 17177, 17179, 17181, 17183, 17185, 17187, 17189, 17191, 17193, 17195, 17197, 17199, 17201, 17203, 17205, 17207, 17209, 17211, 17213, 17215, 17217, 17219, 17221, 17223, 17225, 17227, 17229, 17231, 17233, 17235, 17237, 17239, 17241, 17243, 17245, 17247, 17249, 17251, 17253, 17255, 17257, 17259, 17261, 17263, 17265, 17267, 17269, 17271, 17273, 17275, 17277, 17279, 17281, 17283, 17285, 17287, 17289, 17291, 17293, 17295, 17297, 17299, 17301, 17303, 17305, 17307, 17309, 17311, 17313, 17315, 17317, 17319, 17321, 17323, 17325, 17327, 17329, 17331, 17333, 17335, 17337, 17339, 17341, 17343, 17345, 17347, 17349, 17351, 17353, 17355, 17357, 17359, 17361};
    public String state = "";

    public static interface DOORS {

        public static final int[] doors = {49564, 49387, 49388, 49389, 50302, 50303, 50304, 50311, 50312, 50313, 50321, 50322, 50343, 50344, 50275, 50276, 50277};
        public static final int[] guardian_doors = {50346, 50347, 50348, 53949, 55763};
        public static final int[] boss_doors = {50350, 50351, 50352, 53950, 55764};
        public static final int[] end_ladder = {49696, 49698, 49700};
        //
        public static final int[] puzzle_fish_ferret = {49566, 50342};
        public static final int[] puzzle_four_statues = {49625};
        public static final int[] puzzle_levers = {49387};
        public static final int[] puzzle_ice_field = {49335};
        public static final int[] puzzle_floating_ferrets = {54360};
        public static final int[] puzzle_large_crystal = {49504};
        public static final int[] puzzle_sliding_blocks = {54317};
        public static final int[] puzzle_sliding_statues = {49376};
        public static final int[] puzzle_poisonous_maze = {49338};
        //
        public static final int[] skill_collapsing_doorframe = {50282, 50283, 53954, 55742};
        public static final int[] skill_broken_pulley_door = {50299, 50300, 50301, 53960, 55748};
        public static final int[] skill_broken_key_door = {50308, 50309, 50310, 53963, 55751};
        public static final int[] skill_barred_door = {50272, 50273, 50274, 53951, 55739};
        public static final int[] skill_locked_door = {49600, 49602, 49603, 50288, 50289, 52381, 52382, 53956};
        public static final int[] skill_padlocked_door = {50294, 50295, 53958, 55746};
        public static final int[] skill_vine_covered_door = {50324, 50325, 53968, 55756};
        public static final int[] skill_liquid_lock_door = {50336, 50337, 53972, 55760};
        public static final int[] skill_rune_covered_door = {49540, 49541, 49542, 53994};
        public static final int[] skill_wooden_barricade = {50317, 50318, 50319, 53966, 55754};
        //
        public static final int[] blue_triangle = {50385, 50449, 50513, 53916, 55707};
        public static final int[] blue_diamond = {50386, 50450, 50514, 53917, 55708};
        public static final int[] blue_rectangle = {50387, 50451, 50515, 53918, 55709};
        public static final int[] blue_pentagon = {50388, 50452, 50516, 53919, 55710};
        public static final int[] blue_corner = {50389, 50453, 50517, 53920, 55711};
        public static final int[] blue_crescent = {50390, 50454, 50518, 53921, 55712};
        public static final int[] blue_wedge = {50391, 50455, 50519, 53922, 55713};
        public static final int[] blue_shield = {50392, 50456, 50520, 53923, 55714};
        //
        public static final int[] crimson_triangle = {50401, 50465, 50529, 53932, 55723};
        public static final int[] crimson_diamond = {50402, 50466, 50530, 53933, 55724};
        public static final int[] crimson_rectangle = {50403, 50467, 50531, 53934, 55725};
        public static final int[] crimson_pentagon = {50404, 50468, 50532, 53935, 55726};
        public static final int[] crimson_corner = {50405, 50469, 50533, 53936, 55727};
        public static final int[] crimson_crescent = {50406, 50470, 50534, 53937, 55728};
        public static final int[] crimson_wedge = {50407, 50471, 50535, 53938, 55729};
        public static final int[] crimson_shield = {50408, 50472, 50536, 53939, 55730};
        //
        public static final int[] gold_triangle = {50409, 50473, 50537, 53940, 55731};
        public static final int[] gold_diamond = {50410, 50474, 50538, 53941, 55732};
        public static final int[] gold_rectangle = {50411, 50475, 50539, 53942, 55733};
        public static final int[] gold_pentagon = {50412, 50476, 50540, 53943, 55734};
        public static final int[] gold_corner = {50413, 50477, 50541, 53944, 55735};
        public static final int[] gold_crescent = {50414, 50478, 50542, 53945, 55736};
        public static final int[] gold_wedge = {50415, 50479, 50543, 53946, 55737};
        public static final int[] gold_shield = {50416, 50480, 50544, 53947, 55738};
        //
        public static final int[] green_triangle = {50377, 50441, 50505, 53908, 55699};
        public static final int[] green_diamond = {50378, 50442, 50506, 53909, 55700};
        public static final int[] green_rectangle = {50379, 50443, 50507, 53910, 55701};
        public static final int[] green_pentagon = {50380, 50444, 50508, 53911, 55702};
        public static final int[] green_corner = {50381, 50445, 50509, 53912, 55703};
        public static final int[] green_crescent = {50382, 50446, 50510, 53913, 55704};
        public static final int[] green_wedge = {50383, 50447, 50511, 53914, 55705};
        public static final int[] green_shield = {50384, 50448, 50512, 53915, 55706};
        //
        public static final int[] orange_triangle = {50353, 50417, 50481, 53884, 55675};
        public static final int[] orange_diamond = {50354, 50418, 50482, 53885, 55676};
        public static final int[] orange_rectangle = {50355, 50419, 50483, 53886, 55677};
        public static final int[] orange_pentagon = {50356, 50420, 50484, 53887, 55678};
        public static final int[] orange_corner = {50357, 50421, 50485, 53888, 55679};
        public static final int[] orange_crescent = {50358, 50422, 50486, 53889, 55680};
        public static final int[] orange_wedge = {50359, 50423, 50487, 53890, 55681};
        public static final int[] orange_shield = {50360, 50424, 50488, 53891, 55682};
        //
        public static final int[] purple_triangle = {50393, 50457, 50521, 53924, 55715};
        public static final int[] purple_diamond = {50394, 50458, 50522, 53925, 55716};
        public static final int[] purple_rectangle = {50395, 50459, 50523, 53926, 55717};
        public static final int[] purple_pentagon = {50396, 50460, 50524, 53927, 55718};
        public static final int[] purple_corner = {50397, 50461, 50525, 53928, 55719};
        public static final int[] purple_crescent = {50398, 50462, 50526, 53929, 55720};
        public static final int[] purple_wedge = {50399, 50463, 50527, 53930, 55721};
        public static final int[] purple_shield = {50400, 50464, 50528, 53931, 55722};
        //
        public static final int[] silver_triangle = {50361, 50425, 50489, 53892, 55683};
        public static final int[] silver_diamond = {50362, 50426, 50490, 53893, 55684};
        public static final int[] silver_rectangle = {50363, 50427, 50491, 53894, 55685};
        public static final int[] silver_pentagon = {50364, 50428, 50492, 53895, 55686};
        public static final int[] silver_corner = {50365, 50429, 50493, 53896, 55687};
        public static final int[] silver_crescent = {50366, 50430, 50494, 53897, 55688};
        public static final int[] silver_wedge = {50367, 50431, 50495, 53898, 55689};
        public static final int[] silver_shield = {50368, 50432, 50496, 53899, 55690};
        //
        public static final int[] yellow_triangle = {50369, 50433, 50497, 53900, 55691};
        public static final int[] yellow_diamond = {50370, 50434, 50498, 53901, 55692};
        public static final int[] yellow_rectangle = {50371, 50435, 50499, 53902, 55693};
        public static final int[] yellow_pentagon = {50372, 50436, 50500, 53903, 55694};
        public static final int[] yellow_corner = {50373, 50437, 50501, 53904, 55695};
        public static final int[] yellow_crescent = {50374, 50438, 50502, 53905, 55696};
        public static final int[] yellow_wedge = {50375, 50439, 50503, 53906, 55697};
        public static final int[] yellow_shield = {50376, 50440, 50504, 53907, 55698};
        //
    }

    public static interface BLOCKS {

        public static final int[] skill_dark_spirit = {50332, 50333, 50334, 53971, 55759};
        public static final int[] skill_runed_door = {50278, 50279, 50280, 53953, 55741};
        public static final int[] skill_flammable_debris = {50314, 50315, 50316, 53965, 55753};
        public static final int[] skill_pile_of_rocks = {50305, 50306, 50307, 53962, 55750};
        public static final int[] skill_magical_barrier = {50329, 50330, 50331, 53970, 55758};
        //
        public static final int[] blue_corner = {50244};
        public static final int[] blue_crescent = {50245};
        public static final int[] blue_diamond = {50241};
        public static final int[] blue_pentagon = {50243};
        public static final int[] blue_triangle = {50240};
        public static final int[] blue_rectangle = {50242};
        public static final int[] blue_shield = {50247};
        public static final int[] blue_wedge = {50246};
        //
        public static final int[] crimson_corner = {50260};
        public static final int[] crimson_crescent = {50261};
        public static final int[] crimson_diamond = {50257};
        public static final int[] crimson_pentagon = {50259};
        public static final int[] crimson_triangle = {50256};
        public static final int[] crimson_rectangle = {50258};
        public static final int[] crimson_shield = {50263};
        public static final int[] crimson_wedge = {50262};
        //
        public static final int[] gold_corner = {50268};
        public static final int[] gold_crescent = {50269};
        public static final int[] gold_diamond = {50265};
        public static final int[] gold_pentagon = {50267};
        public static final int[] gold_triangle = {50264};
        public static final int[] gold_rectangle = {50266};
        public static final int[] gold_shield = {50271};
        public static final int[] gold_wedge = {50270};
        //
        public static final int[] green_corner = {50236};
        public static final int[] green_crescent = {50237};
        public static final int[] green_diamond = {50233};
        public static final int[] green_pentagon = {50235};
        public static final int[] green_triangle = {50232};
        public static final int[] green_rectangle = {50266};
        public static final int[] green_shield = {50239};
        public static final int[] green_wedge = {50238};
        //
        public static final int[] orange_corner = {50212};
        public static final int[] orange_crescent = {50213};
        public static final int[] orange_diamond = {50209};
        public static final int[] orange_pentagon = {50211};
        public static final int[] orange_triangle = {50208};
        public static final int[] orange_rectangle = {50210};
        public static final int[] orange_shield = {50215};
        public static final int[] orange_wedge = {50214};
        //
        public static final int[] purple_corner = {50252};
        public static final int[] purple_crescent = {50253};
        public static final int[] purple_diamond = {50249};
        public static final int[] purple_pentagon = {50251};
        public static final int[] purple_triangle = {50248};
        public static final int[] purple_rectangle = {50250};
        public static final int[] purple_shield = {50255};
        public static final int[] purple_wedge = {50254};
        //
        public static final int[] silver_corner = {50220};
        public static final int[] silver_crescent = {50221};
        public static final int[] silver_diamond = {50217};
        public static final int[] silver_pentagon = {50219};
        public static final int[] silver_triangle = {50216};
        public static final int[] silver_rectangle = {50218};
        public static final int[] silver_shield = {50223};
        public static final int[] silver_wedge = {50222};
        //
        public static final int[] yellow_corner = {50228};
        public static final int[] yellow_crescent = {50229};
        public static final int[] yellow_diamond = {50225};
        public static final int[] yellow_pentagon = {50227};
        public static final int[] yellow_triangle = {50224};
        public static final int[] yellow_rectangle = {50226};
        public static final int[] yellow_shield = {50231};
        public static final int[] yellow_wedge = {50230};
    }

    public static interface KEYS {

        public static final int[] blue_corner = {18274};
        public static final int[] blue_crescent = {18276};
        public static final int[] blue_diamond = {18268};
        public static final int[] blue_pentagon = {18272};
        public static final int[] blue_triangle = {18266};
        public static final int[] blue_rectangle = {18270};
        public static final int[] blue_shield = {18280};
        public static final int[] blue_wedge = {18278};
        //
        public static final int[] crimson_corner = {18306};
        public static final int[] crimson_crescent = {18308};
        public static final int[] crimson_diamond = {18300};
        public static final int[] crimson_pentagon = {18304};
        public static final int[] crimson_triangle = {18298};
        public static final int[] crimson_rectangle = {18302};
        public static final int[] crimson_shield = {18312};
        public static final int[] crimson_wedge = {18310};
        //
        public static final int[] gold_corner = {18322};
        public static final int[] gold_crescent = {18324};
        public static final int[] gold_diamond = {18316};
        public static final int[] gold_pentagon = {18320};
        public static final int[] gold_triangle = {18314};
        public static final int[] gold_rectangle = {18318};
        public static final int[] gold_shield = {18328};
        public static final int[] gold_wedge = {18326};
        //
        public static final int[] green_corner = {18258};
        public static final int[] green_crescent = {18260};
        public static final int[] green_diamond = {18252};
        public static final int[] green_pentagon = {18256};
        public static final int[] green_triangle = {18250};
        public static final int[] green_rectangle = {18254};
        public static final int[] green_shield = {18264};
        public static final int[] green_wedge = {18262};
        //
        public static final int[] orange_corner = {18210};
        public static final int[] orange_crescent = {18212};
        public static final int[] orange_diamond = {18204};
        public static final int[] orange_pentagon = {18208};
        public static final int[] orange_triangle = {18202};
        public static final int[] orange_rectangle = {18206};
        public static final int[] orange_shield = {18216};
        public static final int[] orange_wedge = {18214};
        //
        public static final int[] purple_corner = {18290};
        public static final int[] purple_crescent = {18292};
        public static final int[] purple_diamond = {18284};
        public static final int[] purple_pentagon = {18288};
        public static final int[] purple_triangle = {18282};
        public static final int[] purple_rectangle = {18286};
        public static final int[] purple_shield = {18296};
        public static final int[] purple_wedge = {18294};
        //
        public static final int[] silver_corner = {18266};
        public static final int[] silver_crescent = {18228};
        public static final int[] silver_diamond = {18220};
        public static final int[] silver_pentagon = {18224};
        public static final int[] silver_triangle = {18218};
        public static final int[] silver_rectangle = {18222};
        public static final int[] silver_shield = {18232};
        public static final int[] silver_wedge = {18230};
        //
        public static final int[] yellow_corner = {18242};
        public static final int[] yellow_crescent = {18244};
        public static final int[] yellow_diamond = {18236};
        public static final int[] yellow_pentagon = {18240};
        public static final int[] yellow_triangle = {18234};
        public static final int[] yellow_rectangle = {18238};
        public static final int[] yellow_shield = {18248};
        public static final int[] yellow_wedge = {18246};
    }
    public ArrayList<Integer> keys = new ArrayList<Integer>();
    public ArrayList<Integer> doors = new ArrayList<Integer>();
    public ArrayList<Integer> blocks = new ArrayList<Integer>();

    public ArrayList<Integer> getAllKeys() {
        if (!keys.isEmpty()) {
            return keys;
        }
        Field[] fs = KEYS.class.getDeclaredFields();
        ArrayList<Integer> result = new ArrayList<Integer>();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    for (Integer i : (int[]) f.get(KEYS.class)) {
                        result.add(i);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        keys.addAll(result);
        return result;
    }

    public ArrayList<Integer> getKeyByName(String s) {
        Field[] fs = KEYS.class.getDeclaredFields();
        ArrayList<Integer> result = new ArrayList<Integer>();
        for (Field f : fs) {
            if (f.getName().equals(s) && f.getType().equals(int[].class)) {
                try {
                    for (int i : (int[]) f.get(KEYS.class)) {
                        result.add(i);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return result;
    }

    public String getKeyName(int id) {
        Field[] fs = KEYS.class.getDeclaredFields();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    int[] keys = (int[]) f.get(KEYS.class);
                    for (int key : keys) {
                        if (key == id) {
                            return f.getName();
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return "";
    }

    public ArrayList<Integer> getAllDoors() {
        if (!doors.isEmpty()) {
            return doors;
        }
        Field[] fs = DOORS.class.getDeclaredFields();
        ArrayList<Integer> result = new ArrayList<Integer>();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    for (Integer i : (int[]) f.get(DOORS.class)) {
                        result.add(i);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        doors.addAll(result);
        return result;
    }

    public ArrayList<Integer> getAllBlocks() {
        if (!blocks.isEmpty()) {
            return blocks;
        }
        Field[] fs = BLOCKS.class.getDeclaredFields();
        ArrayList<Integer> result = new ArrayList<Integer>();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    for (Integer i : (int[]) f.get(BLOCKS.class)) {
                        result.add(i);
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        blocks.addAll(result);
        return result;
    }

    public String getBlockName(int id) {
        Field[] fs = BLOCKS.class.getDeclaredFields();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    int[] blocks = (int[]) f.get(BLOCKS.class);
                    for (int block : blocks) {
                        if (block == id) {
                            return f.getName();
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return "";
    }

    public String getDoorName(int id) {
        Field[] fs = DOORS.class.getDeclaredFields();
        for (Field f : fs) {
            if (f.getType().equals(int[].class)) {
                try {
                    int[] doors = (int[]) f.get(DOORS.class);
                    for (int door : doors) {
                        if (door == id) {
                            return f.getName();
                        }
                    }
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        return "";
    }

    public static interface PUZZLES {

        public static Puzzle flying_ghosts = new Puzzle() {

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return r.getNearestNPC(10985, 10986) != null;
            }

            @Override
            public int perform(Room r, Dungeoneer methods) {
                RSNPC monster = r.getNearestMonster(10985);
                if (monster != null) {
                    if ((methods.players.getMyPlayer().getInteracting() != null && !methods.players.getMyPlayer().getInteracting().equals(monster)) || methods.players.getMyPlayer().isIdle()) {
                        if (monster.getHPPercent() > 0) {
                            if (monster.isOnScreen() && monster.doAction("Attack")) {
                                return methods.random(1300, 1800);
                            } else if (!methods.players.getMyPlayer().isMoving() || methods.calc.distanceTo(methods.walking.getDestination()) < 3) {
                                if (methods.calc.distanceTo(monster.getLocation()) <= 3) {
                                    return 0;
                                }
                                methods.walking.walkTo(monster.getLocation());
                                return methods.random(900, 1300);
                            }
                        } else {
                            return methods.random(500, 900);
                        }
                    } else {
                        return methods.random(500, 900);
                    }
                } else {
                    r.setPuzzleSolved(true);
                }
                return -1;
            }

            @Override
            public String getName() {
                return "Flying Ghosts";
            }

            @Override
            public boolean killMonsters() {
                return false;
            }
        };
        public static Puzzle sliding_statues = new Puzzle() {

            private Dungeoneer methods = null;

            @Override
            public String getName() {
                return "Sliding Statues";
            }

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return r.getNearestNPC(10946, 10947, 10948, 10949, 10958, 10959, 10960, 10961) != null;
            }

            @Override
            public int perform(Room r, Dungeoneer d) {
                this.methods = d;
                RSObject[] objs = r.getAllObjects();
                if (objs != null) {
                    ArrayList<RSArea> carpets = new ArrayList<RSArea>();
                    for (RSObject obj : objs) {
                        if (obj.getID() == 50766) {
                            if (methods.getAreaContaining(obj.getLocation(), carpets) == null) {
                                carpets.add(methods.getAreaAroundObject(obj, r));
                            }
                        }
                    }
                    if (carpets.size() != 4) {
                        return -1;
                    }
                    RSNPC example1NPC1 = r.getNearestNPC(10946);
                    RSNPC example1NPC2 = r.getNearestNPC(10947);
                    RSNPC example2NPC1 = r.getNearestNPC(10948);
                    RSNPC example2NPC2 = r.getNearestNPC(10949);
                    RSArea example1Carpet = methods.getAreaContaining(example1NPC1.getLocation(), carpets);
                    RSArea example2Carpet = methods.getAreaContaining(example2NPC1.getLocation(), carpets);
                    Point example1NPC1coord = new Point(example1NPC1.getLocation().getX() - example1Carpet.getX(), example1NPC1.getLocation().getY() - example1Carpet.getY());
                    Point example1NPC2coord = new Point(example1NPC2.getLocation().getX() - example1Carpet.getX(), example1NPC2.getLocation().getY() - example1Carpet.getY());
                    Point example2NPC1coord = new Point(example2NPC1.getLocation().getX() - example2Carpet.getX(), example2NPC1.getLocation().getY() - example2Carpet.getY());
                    Point example2NPC2coord = new Point(example2NPC2.getLocation().getX() - example2Carpet.getX(), example2NPC2.getLocation().getY() - example2Carpet.getY());

                    RSNPC do1NPC1 = r.getNearestNPC(10958);
                    RSNPC do1NPC2 = r.getNearestNPC(10959);
                    RSNPC do2NPC1 = r.getNearestNPC(10960);
                    RSNPC do2NPC2 = r.getNearestNPC(10961);
                    RSArea do1Carpet = methods.getAreaContaining(do1NPC1.getLocation(), carpets);
                    RSArea do2Carpet = methods.getAreaContaining(do2NPC1.getLocation(), carpets);
                    Point do1NPC1coord = new Point(do1NPC1.getLocation().getX() - do1Carpet.getX(), do1NPC1.getLocation().getY() - do1Carpet.getY());
                    Point do1NPC2coord = new Point(do1NPC2.getLocation().getX() - do1Carpet.getX(), do1NPC2.getLocation().getY() - do1Carpet.getY());
                    Point do2NPC1coord = new Point(do2NPC1.getLocation().getX() - do2Carpet.getX(), do2NPC1.getLocation().getY() - do2Carpet.getY());
                    Point do2NPC2coord = new Point(do2NPC2.getLocation().getX() - do2Carpet.getX(), do2NPC2.getLocation().getY() - do2Carpet.getY());
                    Statue[] statues = {
                        new Statue(do1NPC1, example1NPC1, do1NPC1coord, example1NPC1coord),
                        new Statue(do1NPC2, example1NPC2, do1NPC2coord, example1NPC2coord),
                        new Statue(do2NPC1, example2NPC1, do2NPC1coord, example2NPC1coord),
                        new Statue(do2NPC2, example2NPC2, do2NPC2coord, example2NPC2coord)
                    };
                    for (Statue statue : statues) {
                        RSTile currTile = statue.npc.getLocation();
                        int cX = currTile.getX();
                        int cY = currTile.getY();
                        Point curr = statue.loc;
                        Point real = statue.eloc;
                        if (curr.x < real.x && tileEmpty(new RSTile(cX + 1, cY), statues)) {
                            if (tileEmpty(new RSTile(cX - 1, cY), statues)) {
                                push(statue.npc, Wall.EAST);
                            } else {
                                pull(statue.npc, Wall.EAST);
                            }
                            return methods.random(500, 900);
                        } else if (curr.x > real.x && tileEmpty(new RSTile(cX - 1, cY), statues)) {
                            if (tileEmpty(new RSTile(cX + 1, cY), statues)) {
                                push(statue.npc, Wall.WEST);
                            } else {
                                pull(statue.npc, Wall.WEST);
                            }
                            return methods.random(500, 900);
                        } else if (curr.y < real.y && tileEmpty(new RSTile(cX, cY + 1), statues)) {
                            if (tileEmpty(new RSTile(cX, cY - 1), statues)) {
                                push(statue.npc, Wall.NORTH);
                            } else {
                                pull(statue.npc, Wall.NORTH);
                            }
                            return methods.random(500, 900);
                        } else if (curr.y > real.y && tileEmpty(new RSTile(cX, cY - 1), statues)) {
                            if (tileEmpty(new RSTile(cX, cY + 1), statues)) {
                                push(statue.npc, Wall.SOUTH);
                            } else {
                                pull(statue.npc, Wall.SOUTH);
                            }
                            return methods.random(500, 900);
                        }
                    }
                }
                r.setPuzzleSolved(true);
                return -1;
            }

            public boolean tileEmpty(RSTile t, Statue[] statues) {
                for (Statue statue : statues) {
                    if (statue.npc.getLocation().equals(t)) {
                        return false;
                    }
                }
                return true;
            }

            private void push(RSNPC statue, int direction) {
                if (methods.players.getMyPlayer().isIdle()) {
                    int x = statue.getLocation().getX();
                    int y = statue.getLocation().getY();
                    if (direction == Wall.NORTH) {
                        RSTile south = new RSTile(x, y - 1);
                        if (methods.players.getMyPlayer().getLocation().equals(south)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(south)) {
                                methods.tiles.doAction(south, "Walk");
                            } else {
                                methods.walking.walkTo(south, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.SOUTH) {
                        RSTile north = new RSTile(x, y + 1);
                        if (methods.players.getMyPlayer().getLocation().equals(north)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(north)) {
                                methods.tiles.doAction(north, "Walk");
                            } else {
                                methods.walking.walkTo(north, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.EAST) {
                        RSTile west = new RSTile(x - 1, y);
                        if (methods.players.getMyPlayer().getLocation().equals(west)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(west)) {
                                methods.tiles.doAction(west, "Walk");
                            } else {
                                methods.walking.walkTo(west, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.WEST) {
                        RSTile east = new RSTile(x + 1, y);
                        if (methods.players.getMyPlayer().getLocation().equals(east)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(east)) {
                                methods.tiles.doAction(east, "Walk");
                            } else {
                                methods.walking.walkTo(east, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    }
                }
            }

            private void pull(RSNPC statue, int direction) {
                if (methods.players.getMyPlayer().isIdle()) {
                    int x = statue.getLocation().getX();
                    int y = statue.getLocation().getY();
                    if (direction == Wall.NORTH) {
                        RSTile north = new RSTile(x, y + 1);
                        if (methods.players.getMyPlayer().getLocation().equals(north)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(north)) {
                                methods.tiles.doAction(north, "Walk");
                            } else {
                                methods.walking.walkTo(north, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.SOUTH) {
                        RSTile south = new RSTile(x, y - 1);
                        if (methods.players.getMyPlayer().getLocation().equals(south)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(south)) {
                                methods.tiles.doAction(south, "Walk");
                            } else {
                                methods.walking.walkTo(south, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.EAST) {
                        RSTile east = new RSTile(x + 1, y);
                        if (methods.players.getMyPlayer().getLocation().equals(east)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(east)) {
                                methods.tiles.doAction(east, "Walk");
                            } else {
                                methods.walking.walkTo(east, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    } else if (direction == Wall.WEST) {
                        RSTile west = new RSTile(x - 1, y);
                        if (methods.players.getMyPlayer().getLocation().equals(west)) {
                            statue.doAction("Push");
                            methods.sleep(700, 1200);
                            int c = 0;
                            while (statue.isMoving() && c < 100) {
                                methods.sleep(20, 30);
                                c++;
                            }
                        } else {
                            if (methods.isFullyOnScreen(west)) {
                                methods.tiles.doAction(west, "Walk");
                            } else {
                                methods.walking.walkTo(west, true);
                            }
                            methods.sleep(700, 1200);
                        }
                    }
                }
            }

            @Override
            public boolean killMonsters() {
                return true;
            }

            class Statue {

                public RSNPC npc, example;
                public Point loc, eloc;

                public Statue(RSNPC npc, RSNPC example, Point loc, Point eloc) {
                    this.npc = npc;
                    this.example = example;
                    this.loc = loc;
                    this.eloc = eloc;
                }
            }
        };
        public static Puzzle start_room = new Puzzle() {

            public Dungeoneer methods;

            @Override
            public String getName() {
                return "Start room";
            }

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return r.getNearestNPC("Smuggler") != null && !methods.containsAllItems(16295, 16361, 17678, 17883, 17754, 17490, 17794, 17796);
            }

            @Override
            public int perform(Room r, Dungeoneer m) {
                this.methods = m;
                if (methods.inventory.contains(19650)) {
                    if (methods.inventory.getItem(19650).doAction("Open")) {
                        return methods.random(900, 1200);
                    }
                    return 0;
                } else if (r.getGroundItems() != null) {
                    RSGroundItem item = r.getNearestGroundItem();
                    if (item != null) {
                        if (!methods.players.getMyPlayer().isMoving()) {
                            if (item.isOnScreen() && methods.doAction(item, "Take")) {
                                return methods.random(1300, 1800);
                            } else if (!methods.players.getMyPlayer().isMoving() || methods.calc.distanceTo(methods.walking.getDestination()) < 3) {
                                if (methods.calc.distanceTo(item.getLocation()) <= 3) {
                                    return 0;
                                }
                                methods.walking.walkTo(item.getLocation());
                                return methods.random(900, 1300);
                            }
                        } else {
                            return methods.random(500, 900);
                        }
                    } else {
                        return methods.random(500, 800);
                    }
                    return methods.random(500, 900);
                } else if (methods.interfaces.get(956).isValid() ? methods.shopInventoryContains(methods.expensiveItemsInt) : methods.inventory.containsOneOf(methods.expensiveItemsInt)) {
                    if (methods.interfaces.get(956).isValid()) {
                        java.util.List<Integer> ids = Arrays.asList(methods.expensiveItemsInteger);
                        Collections.shuffle(ids);
                        for (int id : ids) {
                            if (!methods.shopInventoryContains(id)) {
                                continue;
                            }
                            int count = methods.shopInventoryCount(id);
                            if (count == 1) {
                                methods.sellItem(id, "Sell 1");
                            } else if (count == 5) {
                                methods.sellItem(id, "Sell 5");
                            } else if (count == 10) {
                                methods.sellItem(id, "Sell 10");
                            } else {
                                methods.sellItem(id, "Sell 50");
                            }
                            methods.sleep(700, 900);
                        }
                    } else {
                        RSNPC smuggler = r.getNearestNPC("Smuggler");
                        if (smuggler != null) {
                            if (methods.players.getMyPlayer().isIdle() && smuggler.isOnScreen() && smuggler.doAction("Trade")) {
                                return methods.random(1300, 1600);
                            } else {
                                if (methods.players.getMyPlayer().isIdle() || methods.calc.distanceTo(methods.walking.getDestination()) < 3) {
                                    if (methods.calc.distanceTo(smuggler.getLocation()) < 3) {
                                        return 0;
                                    }
                                    methods.walking.walkTo(smuggler.getLocation());
                                }
                            }
                            return methods.random(500, 800);
                        }
                    }
                    return methods.random(500, 900);
                } else if (methods.interfaces.get(956).isValid() ? (methods.shopInventoryCount(18201) >= 1320 && !methods.shopInventoryContains(19650)) : (methods.inventory.getCount(true, 18201) > 1320 && !methods.inventory.contains(19650))) {
                    if (methods.interfaces.get(956).isValid()) {
                        RSComponent toolkitComponent = methods.interfaces.get(956).getComponent(24).getComponent(254);
                        if (methods.interfaces.get(956).getComponent(24).getArea().contains(toolkitComponent.getArea())) {
                            toolkitComponent.doAction("Buy 1");
                        } else {
                            methods.interfaces.scrollTo(methods.interfaces.get(956).getComponent(24).getComponent(254), methods.interfaces.get(956).getComponent(25));
                        }
                        methods.sleep(500, 900);
                    } else {
                        RSNPC smuggler = r.getNearestNPC("Smuggler");
                        if (smuggler != null) {
                            if (methods.players.getMyPlayer().isIdle() && smuggler.isOnScreen() && smuggler.doAction("Trade")) {
                                return methods.random(500, 900);
                            } else {
                                if (methods.players.getMyPlayer().isIdle() || methods.calc.distanceTo(methods.walking.getDestination()) < 3) {
                                    methods.walking.walkTo(smuggler.getLocation());
                                }
                            }
                        }
                    }
                    return methods.random(500, 900);
                } else if (methods.interfaces.get(956).isValid()) {
                    methods.interfaces.get(956).getComponent(18).doAction("Close");
                    return methods.random(500, 900);
                }
                r.setPuzzleSolved(true);
                return -1;
            }

            @Override
            public boolean killMonsters() {
                return false;
            }
        };
        public static Puzzle follow_the_leader = new Puzzle() {

            Dungeoneer methods;
            int lastAnim = -1;

            @Override
            public String getName() {
                return "Follow the Leader";
            }

            @Override
            public boolean killMonsters() {
                return true;
            }

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return r.getNearestNPC(10968) != null;
            }

            @Override
            public int perform(Room r, Dungeoneer m) {
                methods = m;
                RSNPC statue = r.getNearestNPC(10968);
                RSObject pad = getPad(r, statue);
                if (methods.players.getMyPlayer().getLocation().equals(pad.getLocation())) {
                    lastAnim = statue.getAnimation();
                    int component = -1;
                    if (lastAnim == 863) {
                        component = 3;
                    } else if (lastAnim == 855) {
                        component = 24;
                    } else if (lastAnim == 856) {
                        component = 29;
                    } else if (lastAnim == 861) {
                        component = 34;
                    } else if (lastAnim == 860) {
                        component = 39;
                    } else if (lastAnim == 858) {
                        r.setPuzzleSolved(true);
                    } else if (lastAnim == -1) {
                        return methods.random(10, 20);
                    }
                    if (component != -1) {
                        methods.interfaces.get(1188).getComponent(component).doAction("Continue");
                    }
                } else {
                    if (methods.players.getMyPlayer().isIdle() || methods.calc.distanceTo(methods.walking.getDestination()) < 3) {
                        methods.walking.walkTo(pad.getLocation());
                    }
                }
                return -1;
            }

            public RSObject getPad(Room r, RSNPC npc) {
                RSObject cur = null;
                double dist = -1;
                for (RSTile t : r.area.getTileArray()) {
                    RSObject[] objs = methods.objects.getAt(new RSTile(t.getX(), t.getY()), 2);
                    for (RSObject o : objs) {
                        if (o.getID() == 52206) {
                            double distTmp = methods.calc.distanceBetween(npc.getLocation(), o.getLocation());
                            if (cur == null) {
                                dist = distTmp;
                                cur = o;
                            } else if (distTmp < dist) {
                                cur = o;
                                dist = distTmp;
                            }
                            break;
                        }
                    }
                }
                return cur;
            }
        };
        public static Puzzle finish_room = new Puzzle() {

            @Override
            public String getName() {
                return "Finish dungeon";
            }

            @Override
            public boolean killMonsters() {
                throw new UnsupportedOperationException("Not supported yet.");
            }

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return false;
            }

            @Override
            public int perform(Room r, Dungeoneer methods) {
                throw new UnsupportedOperationException("Not supported yet.");
            }
        };
        public static Puzzle levers = new Puzzle() {

            int runEnergy = -1;

            @Override
            public String getName() {
                return "Levers";
            }

            @Override
            public boolean killMonsters() {
                return true;
            }

            @Override
            public boolean activate(Room r, Dungeoneer methods) {
                return r.getNearestObject(49381, 49382, 49383) != null;
            }

            @Override
            public int perform(Room r, Dungeoneer methods) {
                if (runEnergy == -1) {
                    runEnergy = methods.random(30, 50);
                }
                if (methods.walking.getEnergy() < runEnergy) {
                    methods.walking.rest(100);
                    return methods.random(300, 500);
                }
                if (!methods.walking.isRunEnabled()) {
                    methods.walking.setRun(true);
                }
                RSObject o = r.getNearestObject(49381, 49382, 49383);
                if (o != null) {
                    if (methods.players.getMyPlayer().isMoving()) {
                        return methods.random(10, 30);
                    }
                    if (methods.isFullyOnScreen(o.getLocation())) {
                        if (o.doAction("Pull")) {
                            RSObject next = r.getNearestObjectExcluding(o, 49381, 49382, 49383);
                            if (next != null) {
                                methods.sleep(900, 1300);
                                while (!methods.players.getMyPlayer().isIdle()) {
                                    methods.sleep(10, 30);
                                }
                                if (methods.isFullyOnScreen(next.getLocation())) {
                                    o.doAction("Pull");
                                } else {
                                    methods.walking.walkTileMM(next.getLocation());
                                    methods.sleep(100, 300);
                                }
                            } else {
                                r.setPuzzleSolved(true);
                                return -1;
                            }
                        }
                    } else {
                        methods.walking.walkTileMM(o.getLocation());
                        methods.sleep(100, 300);
                    }
                    return methods.random(100, 300);
                } else {
                    r.setPuzzleSolved(true);
                    return -1;
                }
            }
        };
    }

    public class Invy {

        public RSItem[] getItems() {

            return null;
        }
    }

    public boolean containsAllItems(int... ids) {
        for (int id : ids) {
            if ((interfaces.get(956).isValid() ? !shopInventoryContains(id) : !inventory.contains(id))) {
                return false;
            }
        }
        return true;
    }

    public void sellItem(int id, String action) {
        for (RSComponent r : interfaces.get(957).getComponent(0).getComponents()) {
            if (r.getComponentID() == id) {
                r.doAction(action);
                sleep(500, 900);
                return;
            }
        }
    }

    public boolean shopInventoryContains(int... ids) {
        for (RSComponent r : interfaces.get(957).getComponent(0).getComponents()) {
            for (int id : ids) {
                if (r.getComponentID() == id) {
                    return true;
                }
            }
        }
        return false;
    }

    public int shopInventoryCount(int... ids) {
        int c = 0;
        for (RSComponent r : interfaces.get(957).getComponent(0).getComponents()) {
            for (int id : ids) {
                if (r.getComponentID() == id) {
                    c += r.getComponentStackSize();
                }
            }
        }
        return c;
    }

    public boolean doAction(RSGroundItem rsi, String action) {
        if (rsi == null) {
            return false;
        }
        RSTile t = rsi.getLocation();
        boolean objectUnderneath = false;
        RSObject[] os = objects.getAllAt(rsi.getLocation());
        if (os != null) {
            for (RSObject o : os) {
                if (o.getType().equals(RSObject.Type.INTERACTABLE)) {
                    objectUnderneath = true;
                }
            }
        }
        Point p = calc.tileToScreen(t, random(0.45, 0.55), random(0.45, 0.55), (objectUnderneath ? 400 : 0));
        if (p == null) {
            return false;
        }
        mouse.move(new Point(p.x, p.y));
        int c = 0;
        while (!menu.doAction(action) && c < 5) {
            c++;
        }
        return c < 5;
    }
    public ArrayList<Puzzle> puzzles = new ArrayList<Puzzle>();
    public ArrayList<RSTile> badTiles = new ArrayList<RSTile>();

    public ArrayList<Puzzle> getAllPuzzles() {
        if (!puzzles.isEmpty()) {
            return puzzles;
        }
        Field[] fs = PUZZLES.class.getDeclaredFields();
        ArrayList<Puzzle> result = new ArrayList<Puzzle>();
        for (Field f : fs) {
            if (f.getType().equals(Puzzle.class)) {
                try {
                    result.add((Puzzle) f.get(PUZZLES.class));
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        }
        puzzles.addAll(result);
        return puzzles;
    }

    public interface Puzzle {

        public String getName();

        public boolean killMonsters();

        public boolean activate(Room r, Dungeoneer methods);

        public int perform(Room r, Dungeoneer methods);
    }
    public ArrayList<Room> rooms = new ArrayList<Room>();
    public boolean firstLoop = true;

    @Override
    public int loop() {
        mouse.setSpeed(random(3, 6));
        if (!game.isLoggedIn()) {
            return 50;
        }
        if (firstLoop) {
            new LocationGetter().start();
            firstLoop = false;
        }
        if (inDungeon()) {
            Room r = getCurrentRoom();
            if (r != null) {
                prevRoom = r;
                if (puzzle == null) {
                    for (Puzzle p : getAllPuzzles()) {
                        if (p.activate(r, this)) {
                            if (!p.killMonsters() || r.getMonsters() == null) {
                                int i = p.perform(r, this);
                                if (i != -1) {
                                    puzzle = p;
                                    puzzleStart = System.currentTimeMillis();
                                    log("Puzzle \"" + puzzle.getName() + "\" started");
                                    state = "Solving puzzle: " + p.getName();
                                    return i;
                                }
                            }
                        }
                    }
                    if (r.isPuzzleSolved()) {
                        puzzle = null;
                    }
                }
                if (r.getMonsters() != null) {
                    RSNPC monster = r.getNearestMonster();
                    if (monster != null) {
                        state = "Killing monsters";
                        if (players.getMyPlayer().getInteracting() == null || players.getMyPlayer().getInteracting().getHPPercent() == 0 || players.getMyPlayer().isIdle()) {
                            if (monster.getHPPercent() > 0) {
                                if (monster.isOnScreen() && monster.doAction("Attack")) {
                                    return random(1300, 1800);
                                } else if (!players.getMyPlayer().isMoving() || calc.distanceTo(walking.getDestination()) < 3) {
                                    if (calc.distanceTo(monster.getLocation()) <= 3) {
                                        return 0;
                                    }
                                    walking.walkTo(monster.getLocation());
                                    return random(900, 1300);
                                } else {
                                    return random(500, 900);
                                }
                            } else {
                                return random(10, 50);
                            }
                        } else {
                            return random(500, 900);
                        }
                    } else {
                        return random(500, 900);
                    }
                }
                if (puzzle != null) {
                    if (r.getMonsters() != null && puzzle.killMonsters()) {
                        return random(500, 900);
                    }
                    if (puzzle.activate(r, this)) {
                        int i = puzzle.perform(r, this);
                        if (i != -1) {
                            state = "Solving puzzle: " + puzzle.getName();
                            return i;
                        }
                    }
                    long timeTook = System.currentTimeMillis() - puzzleStart;
                    log("Puzzle \"" + puzzle.getName() + "\" finished, took: " + formatTime(timeTook));
                    puzzle = null;
                }
                if (r.getKeys() != null) {
                    RSGroundItem key = r.getNearestKey();
                    if (key != null) {
                        String name = getKeyName(key.getItem().getID()).replace("_", " ").trim();
                        name = name.substring(0, 1).toUpperCase() + name.substring(1);
                        state = "Collecting key: " + name;
                        if (!players.getMyPlayer().isMoving()) {
                            if (key.isOnScreen() && key.doAction("Take")) {
                                return random(1300, 1800);
                            } else if (!players.getMyPlayer().isMoving() || calc.distanceTo(walking.getDestination()) < 3) {
                                if (calc.distanceTo(key.getLocation()) <= 3) {
                                    return 0;
                                }
                                walking.walkTo(key.getLocation());
                                return random(900, 1300);
                            } else {
                                return random(500, 900);
                            }
                        } else {
                            return random(500, 900);
                        }
                    } else {
                        return random(500, 900);
                    }
                }
                if (r.getDoorBlocks() != null) {
                    RSObject block = r.getNearestDoorBlock();
                    if (block != null) {
                        state = "Unlocking/Unblocking doors";
                        if (!players.getMyPlayer().isMoving() && players.getMyPlayer().getAnimation() != 13798) {
                            if (block.isOnScreen() && block.doAction("Unlock")) {
                                return random(1300, 1800);
                            } else if (!players.getMyPlayer().isMoving() || calc.distanceTo(walking.getDestination()) < 3) {
                                if (calc.distanceTo(block.getLocation()) <= 3) {
                                    return 0;
                                }
                                walking.walkTo(block.getLocation());
                                return random(900, 1300);
                            } else {
                                return random(500, 900);
                            }
                        } else {
                            return random(500, 900);
                        }
                    } else {
                        return random(500, 900);
                    }
                }
                if (r.getClosedDoors() != null) {
                    RSObject door = r.getNearestClosedDoor();
                    if (door != null) {
                        state = "Navigating to next room";
                        if (!players.getMyPlayer().isMoving()) {
                            if (door.isOnScreen() && (door.doAction("Enter") || door.doAction("Open"))) {
                                return random(1300, 1800);
                            } else if (!players.getMyPlayer().isMoving() || calc.distanceTo(walking.getDestination()) < 3) {
                                if (calc.distanceTo(door.getLocation()) <= 3) {
                                    return 0;
                                }
                                walking.walkTo(door.getLocation());
                                return random(900, 1300);
                            } else {
                                return random(500, 900);
                            }
                        } else {
                            return random(500, 900);
                        }
                    } else {
                        return random(500, 900);
                    }
                }
                Room[] best = getPathToBestRoom();
                if (best != null) {
                    Room nextRoom = getNextRoom(best);
                    if (nextRoom != null) {
                        RSObject door = getDoorToRoom(nextRoom);
                        if (door != null) {
                            state = "Navigating to best room";
                            if (!players.getMyPlayer().isMoving()) {
                                if (door.isOnScreen() && (door.doAction("Enter") || door.doAction("Open"))) {
                                    return random(1300, 1800);
                                } else if (!players.getMyPlayer().isMoving() || calc.distanceTo(walking.getDestination()) < 3) {
                                    if (calc.distanceTo(door.getLocation()) <= 3) {
                                        return 0;
                                    }
                                    walking.walkTo(door.getLocation());
                                    return random(900, 1300);
                                } else {
                                    return random(500, 900);
                                }
                            } else {
                                return random(500, 900);
                            }
                        } else {
                            state = "Door: null (" + best.length + ";" + door + ")";
                        }
                    } else {
                        state = "Next room: null (" + best.length + ")";
                    }
                } else {
                    state = "Best path: null";
                }
            } else {
                rooms.add(new Room(players.getMyPlayer().getLocation()));
            }
        } else {
            rooms.clear();
        }
        return random(500, 900);
    }

    private String formatTime(long time) {
        long TotalSec = time / 1000;
        long TotalMin = TotalSec / 60;
        long TotalHour = TotalMin / 60;
        int second = (int) TotalSec % 60;
        int minute = (int) TotalMin % 60;
        int hour = (int) TotalHour;
        String res = "";
        res += (hour > 9) ? hour + ":" : "0" + hour + ":";
        res += (minute > 9) ? minute + ":" : "0" + minute + ":";
        res += (second > 9) ? second : "0" + second;
        return res;
    }

    public RSObject getDoorToRoom(Room r) {
        Room curr = getCurrentRoom();
        if (Point.distance(curr.x, curr.y, r.x, r.y) != 1) {
            return null;
        }
        RSTile doorTile = null;
        if (curr.x < r.x) {
            doorTile = curr.getDoorTile(Wall.EAST);
        } else if (curr.x > r.x) {
            doorTile = curr.getDoorTile(Wall.WEST);
        } else if (curr.y < r.y) {
            doorTile = curr.getDoorTile(Wall.NORTH);
        } else if (curr.y > r.y) {
            doorTile = curr.getDoorTile(Wall.SOUTH);
        }
        if (doorTile == null) {
            return null;
        }
        for (RSObject o : objects.getAllAt(doorTile)) {
            if (getAllDoors().contains(o.getID())) {
                return o;
            }
        }
        return null;
    }

    public Room[] getPathToBestRoom() {
        try {
            Room[] best = null;
            for (Room r : rooms) {
                if (r.getClosedDoors() == null && r.getKeys() == null && r.getDoorBlocks() == null) {
                    continue;
                }
                log("Found not completed room: " + r);
                Room[] path = getPath(getCurrentRoom().x, getCurrentRoom().y, r.x, r.y);
                if (path != null) {
                    if (best == null || path.length < best.length) {
                        best = path;
                        log.warning("This is the best one yet");
                    }
                } else {
                    log.warning("Unable to find path");
                }
            }
            log("------ (" + (best == null ? -1 : best.length) + ")");
            return best;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public Room getNextRoom(Room[] path) {
        Room r = getCurrentRoom();
        for (int i = 0; i < path.length - 1; i++) {
            if (r.equals(path[i])) {
                return path[i + 1];
            }
        }
        return null;
    }

    public static interface Wall {

        public static final int NORTH = 0x1;
        public static final int SOUTH = 0x2;
        public static final int EAST = 0x4;
        public static final int WEST = 0x8;
    }

    public class Room {

        public final int index;
        public int x;
        public int y;
        public final RSArea area;
        public final int neighbours;
        public RSTile[] doorLocs = new RSTile[4];
        public RSTile[][] tiles = {};
        public Filter<RSNPC> monstersFilter;
        public Filter<RSGroundItem> keysFilter;
        public Filter<RSGroundItem> groundItemsFilter;
        public Filter<RSObject> blocksFilter;
        public Filter<RSObject> openDoorsFilter;
        public Filter<RSObject> closedDoorsFilter;
        public boolean solved = false;
        private Room parent;

        public Room(RSTile t) {
            this.area = getAreaAround(t);
            this.index = overallIndex++;
            this.neighbours = getNeighboursSetting();
            if (prevRoom != null) {
                int angle = calc.angleToTile(prevRoom.area.getCentralTile());
                if (angle > 45 && angle <= 135) { //NORTH
                    this.x = prevRoom.x;
                    this.y = prevRoom.y - 1;
                }
                if (angle > 135 && angle <= 225) { //WEST
                    this.x = prevRoom.x + 1;
                    this.y = prevRoom.y;
                }
                if (angle > 225 && angle <= 315) { //SOUTH
                    this.x = prevRoom.x;
                    this.y = prevRoom.y + 1;
                }
                if ((angle > 315 && angle <= 359) || (angle >= 0 && angle <= 45)) { //EAST
                    this.x = prevRoom.x - 1;
                    this.y = prevRoom.y;
                }
                log.warning("Found a new room: (" + x + ";" + y + ") indexed " + this.index);
            } else {
                this.x = 0;
                this.y = 0;
                log.warning("Started a new dungeon.");
            }
            this.monstersFilter = new Filter<RSNPC>() {

                @Override
                public boolean accept(RSNPC t) {
                    boolean b = false;
                    if (t.getActions() != null) {
                        for (String action : t.getActions()) {
                            if (action == null) {
                                continue;
                            }
                            if (action.contains("Attack")) {
                                b = true;
                                break;
                            }
                        }
                    }
                    return area.contains(t.getLocation()) && b;
                }
            };
            this.keysFilter = new Filter<RSGroundItem>() {

                @Override
                public boolean accept(RSGroundItem t) {
                    return area.contains(t.getLocation()) && getAllKeys().contains(t.getItem().getID());
                }
            };
            this.groundItemsFilter = new Filter<RSGroundItem>() {

                @Override
                public boolean accept(RSGroundItem t) {
                    return area.contains(t.getLocation()) && !getAllKeys().contains(t.getItem().getID());
                }
            };
            this.blocksFilter = new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    if (!area.contains(t.getLocation()) || !getAllBlocks().contains(t.getID())) {
                        return false;
                    }
                    String s = getBlockName(t.getID());
                    if (s.contains("skill")) {
                        for (RSTile badTile : badTiles) {
                            if (calc.distanceBetween(t.getLocation(), badTile) <= 2) {
                                return false;
                            }
                        }
                        return true;
                    }
                    if (!s.isEmpty()) {
                        ArrayList<Integer> keys = getKeyByName(s);
                        for (RSItem i : inventory.getItems()) {
                            for (Integer id : keys) {
                                if (i.getID() == id) {
                                    return true;
                                }
                            }
                        }
                    }
                    return false;
                }
            };
            this.openDoorsFilter = new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    if (!area.contains(t.getLocation()) || !getAllDoors().contains(t.getID())) {
                        return false;
                    }
                    String s = getDoorName(t.getID());
                    int xT = t.getLocation().getX();
                    int yT = t.getLocation().getY();
                    RSObject[][] surrounding = {objects.getAllAt(new RSTile(xT, yT + 1)), objects.getAllAt(new RSTile(xT, yT - 1)), objects.getAllAt(new RSTile(xT + 1, yT)), objects.getAllAt(new RSTile(xT - 1, yT))};
                    for (RSObject[] everyTile : surrounding) {
                        if (everyTile == null) {
                            continue;
                        }
                        for (RSObject o : everyTile) {
                            if (getAllBlocks().contains(o.getID())) {
                                return false;
                            }
                        }
                    }
                    if (getDoorTile(Wall.NORTH) != null && t.getLocation().equals(getDoorTile(Wall.NORTH)) && getRoom(x, y + 1) != null) {
                        return true;
                    } else if (getDoorTile(Wall.SOUTH) != null && t.getLocation().equals(getDoorTile(Wall.SOUTH)) && getRoom(x, y - 1) != null) {
                        return true;
                    } else if (getDoorTile(Wall.EAST) != null && t.getLocation().equals(getDoorTile(Wall.EAST)) && getRoom(x + 1, y) != null) {
                        return true;
                    } else if (getDoorTile(Wall.WEST) != null && t.getLocation().equals(getDoorTile(Wall.WEST)) && getRoom(x - 1, y) != null) {
                        return true;
                    } else {
                        return false;
                    }
                }
            };
            this.closedDoorsFilter = new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    if (!area.contains(t.getLocation()) || !getAllDoors().contains(t.getID())) {
                        return false;
                    }
                    String s = getDoorName(t.getID());
                    int xT = t.getLocation().getX();
                    int yT = t.getLocation().getY();
                    RSObject[][] surrounding = {objects.getAllAt(new RSTile(xT, yT + 1)), objects.getAllAt(new RSTile(xT, yT - 1)), objects.getAllAt(new RSTile(xT + 1, yT)), objects.getAllAt(new RSTile(xT - 1, yT))};
                    for (RSObject[] everyTile : surrounding) {
                        if (everyTile == null) {
                            continue;
                        }
                        for (RSObject o : everyTile) {
                            if (getAllBlocks().contains(o.getID())) {
                                return false;
                            }
                        }
                    }
                    for (RSTile badTile : badTiles) {
                        if (calc.distanceBetween(t.getLocation(), badTile) <= 2) {
                            return false;
                        }
                    }
                    if (getDoorTile(Wall.NORTH) != null && t.getLocation().equals(getDoorTile(Wall.NORTH)) && getRoom(x, y + 1) == null) {
                        return true;
                    } else if (getDoorTile(Wall.SOUTH) != null && t.getLocation().equals(getDoorTile(Wall.SOUTH)) && getRoom(x, y - 1) == null) {
                        return true;
                    } else if (getDoorTile(Wall.EAST) != null && t.getLocation().equals(getDoorTile(Wall.EAST)) && getRoom(x + 1, y) == null) {
                        return true;
                    } else if (getDoorTile(Wall.WEST) != null && t.getLocation().equals(getDoorTile(Wall.WEST)) && getRoom(x - 1, y) == null) {
                        return true;
                    } else {
                        return false;
                    }
                }
            };
        }

        public Room(int x, int y, int neighbours) {
            this.x = x;
            this.y = y;
            this.neighbours = neighbours;
            this.doorLocs = null;
            this.area = null;
            this.parent = null;
            index = 0;
        }

        public Room(int x, int y, int neighbours, RSTile[] doorLocs, RSArea area, Room parent) {
            this.x = x;
            this.y = y;
            this.neighbours = neighbours;
            this.doorLocs = doorLocs;
            this.area = area;
            this.parent = parent;
            index = 0;
        }

        public RSTile getDoorTile(int wall) {
            if (wall == Wall.NORTH) {
                if (doorLocs[0] != null) {
                    return doorLocs[0].equals(new RSTile(-1, -1)) ? null : doorLocs[0];
                }
                ArrayList<RSTile> northRow = new ArrayList<RSTile>();
                for (RSTile[] rows : getTiles()) {
                    if (rows[rows.length - 2] != null) {
                        northRow.add(getLast(rows));
                    }
                }
                RSTile t = new RSTile(-1, -1);
                for (RSTile tile : northRow) {
                    if (tile == null) {
                        continue;
                    }
                    RSObject[] os = objects.getAllAt(tile);
                    if (os != null) {
                        for (RSObject o : os) {
                            if (isDoor(o)) {
                                t = tile;
                            }
                        }
                    }
                }
                doorLocs[0] = t;
                return t.equals(new RSTile(-1, -1)) ? null : t;
            } else if (wall == Wall.SOUTH) {
                if (doorLocs[1] != null) {
                    return doorLocs[1].equals(new RSTile(-1, -1)) ? null : doorLocs[1];
                }
                ArrayList<RSTile> southRow = new ArrayList<RSTile>();
                for (RSTile[] rows : getTiles()) {
                    if (rows[0] != null) {
                        southRow.add(rows[0]);
                    }
                }
                RSTile t = new RSTile(-1, -1);
                for (RSTile tile : southRow) {
                    if (tile == null) {
                        continue;
                    }
                    RSObject[] os = objects.getAllAt(tile);
                    if (os != null) {
                        for (RSObject o : os) {
                            if (isDoor(o)) {
                                t = tile;
                            }
                        }
                    }
                }
                doorLocs[1] = t;
                return t.equals(new RSTile(-1, -1)) ? null : t;
            } else if (wall == Wall.WEST) {
                if (doorLocs[2] != null) {
                    return doorLocs[2].equals(new RSTile(-1, -1)) ? null : doorLocs[2];
                }
                RSTile[] westRow = getTiles()[0];
                RSTile t = new RSTile(-1, -1);
                for (RSTile tile : westRow) {
                    if (tile == null) {
                        continue;
                    }
                    RSObject[] os = objects.getAllAt(tile);
                    if (os != null) {
                        for (RSObject o : os) {
                            if (isDoor(o)) {
                                t = tile;
                            }
                        }
                    }
                }
                doorLocs[2] = t;
                return t.equals(new RSTile(-1, -1)) ? null : t;
            } else if (wall == Wall.EAST) {
                if (doorLocs[3] != null) {
                    return doorLocs[3].equals(new RSTile(-1, -1)) ? null : doorLocs[3];
                }
                RSTile[] eastRow = getLastRow(getTiles());
                RSTile t = new RSTile(-1, -1);
                for (RSTile tile : eastRow) {
                    if (tile == null) {
                        continue;
                    }
                    RSObject[] os = objects.getAllAt(tile);
                    if (os != null) {
                        for (RSObject o : os) {
                            if (isDoor(o)) {
                                t = tile;
                            }
                        }
                    }
                }
                doorLocs[3] = t;
                return t.equals(new RSTile(-1, -1)) ? null : t;
            }
            return null;
        }

        public RSTile[][] getTiles() {
            if (tiles.length > 0) {
                return tiles;
            }
            RSTile[][] tiles = new RSTile[area.getWidth() + 1][area.getHeight() + 1];
            for (int i = 0; i <= area.getWidth(); ++i) {
                for (int j = 0; j <= area.getHeight(); ++j) {
                    if (area.contains(area.getX() + i, area.getY() + j)) {
                        tiles[i][j] = new RSTile(area.getX() + i, area.getY() + j);
                    }
                }
            }
            this.tiles = tiles;
            return tiles;
        }

        public void setPuzzleSolved(boolean b) {
            solved = b;
        }

        public boolean isPuzzleSolved() {
            return solved;
        }

        public int getNeighboursSetting() {
            int n = 0;
            try {//RSTile[] tiles = area.getTileArray();
                RSTile northDoor = getDoorTile(Wall.NORTH);
                RSTile westDoor = getDoorTile(Wall.WEST);
                RSTile southDoor = getDoorTile(Wall.SOUTH);
                RSTile eastDoor = getDoorTile(Wall.EAST);
                if (northDoor != null) {
                    n |= Wall.NORTH;
                }
                if (westDoor != null) {
                    n |= Wall.WEST;
                }
                if (southDoor != null) {
                    n |= Wall.SOUTH;
                }
                if (eastDoor != null) {
                    n |= Wall.EAST;
                }
            } catch (Exception e) {
            }
            return n;
        }

        public Room[] getNeighbours() {
            ArrayList<Room> neigh = new ArrayList<Room>();
            if ((neighbours & Wall.NORTH) != 0) {
                Room r = getRoom(x, y + 1);
                if (r != null) {
                    r.setParent(clone());
                    neigh.add(r.clone());
                }
            }
            if ((neighbours & Wall.WEST) != 0) {
                Room r = getRoom(x - 1, y);
                if (r != null) {
                    r.setParent(clone());
                    neigh.add(r.clone());
                }
            }
            if ((neighbours & Wall.SOUTH) != 0) {
                Room r = getRoom(x, y - 1);
                if (r != null) {
                    r.setParent(clone());
                    neigh.add(r.clone());
                }
            }
            if ((neighbours & Wall.EAST) != 0) {
                Room r = getRoom(x + 1, y);
                if (r != null) {
                    r.setParent(clone());
                    neigh.add(r.clone());
                }
            }
            if (parent != null) {
                int parentIndx = -1;
                for (int i = 0; i < neigh.size(); i++) {
                    if (neigh.get(i).x == parent.x && neigh.get(i).y == parent.y) {
                        parentIndx = i;
                        break;
                    }
                }
                if (parentIndx >= 0) {
                    neigh.remove(parentIndx);
                }
            }
            return neigh.toArray(new Room[neigh.size()]);
        }

        public boolean gotNeighbour(int direction) {
            return (neighbours & direction) != 0;
        }

        private RSTile[] getLastRow(RSTile[][] rows) {
            for (int i = rows.length - 1; i > 0; i--) {
                ArrayList<RSTile> result = new ArrayList<RSTile>();
                for (RSTile t : rows[i]) {
                    if (t != null) {
                        result.add(t);
                    }
                }
                if (result.isEmpty()) {
                    continue;
                }
                return result.toArray(new RSTile[result.size()]);
            }
            return new RSTile[]{};
        }

        private RSTile getLast(RSTile[] tiles) {
            for (int i = tiles.length - 1; i > 0; i--) {
                if (tiles[i] != null) {
                    return tiles[i];
                }
            }
            return null;
        }

        public RSNPC[] getMonsters() {
            RSNPC[] monsters = npcs.getAll(monstersFilter);
            return monsters.length == 0 ? null : monsters;
        }

        public RSNPC getNearestMonster() {
            return npcs.getNearest(monstersFilter);
        }

        public RSNPC getNearestMonster(final int... ids) {
            return npcs.getNearest(new Filter<RSNPC>() {

                @Override
                public boolean accept(RSNPC t) {
                    boolean i = false;
                    for (int id : ids) {
                        if (id == t.getID()) {
                            i = true;
                        }
                    }
                    boolean b = false;
                    if (t.getActions() != null) {
                        for (String action : t.getActions()) {
                            if (action == null) {
                                continue;
                            }
                            if (action.contains("Attack")) {
                                b = true;
                                break;
                            }
                        }
                    }
                    return area.contains(t.getLocation()) && b && i;
                }
            });
        }

        public RSNPC getNearestNPC(final String... names) {
            return npcs.getNearest(new Filter<RSNPC>() {

                @Override
                public boolean accept(RSNPC t) {
                    boolean i = false;
                    for (String name : names) {
                        if (t.getName().equals(name)) {
                            i = true;
                        }
                    }
                    return area.contains(t.getLocation()) && i;
                }
            });
        }

        public RSNPC getNearestNPC(final int... ids) {
            return npcs.getNearest(new Filter<RSNPC>() {

                @Override
                public boolean accept(RSNPC t) {
                    boolean i = false;
                    for (int id : ids) {
                        if (id == t.getID()) {
                            i = true;
                        }
                    }
                    return area.contains(t.getLocation()) && i;
                }
            });
        }

        public RSObject getNearestObject(final int... ids) {
            return objects.getNearest(new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    boolean i = false;
                    for (int id : ids) {
                        if (id == t.getID()) {
                            i = true;
                        }
                    }
                    return area.contains(t.getLocation()) && i;
                }
            });
        }

        public RSObject getNearestObjectExcluding(final RSObject o, final int... ids) {
            return objects.getNearest(new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    if (t.getLocation().equals(o.getLocation()) && t.getID() == o.getID()) {
                        return false;
                    }
                    boolean i = false;
                    for (int id : ids) {
                        if (id == t.getID()) {
                            i = true;
                        }
                    }
                    return area.contains(t.getLocation()) && i;
                }
            });
        }

        public RSGroundItem[] getKeys() {
            RSGroundItem[] keys = groundItems.getAll(keysFilter);
            return keys.length == 0 ? null : keys;
        }

        public RSGroundItem[] getGroundItems() {
            RSGroundItem[] items = groundItems.getAll(groundItemsFilter);
            return items.length == 0 ? null : items;
        }

        public RSGroundItem getNearestKey() {
            return groundItems.getNearest(keysFilter);
        }

        public RSGroundItem getNearestGroundItem() {
            return groundItems.getNearest(groundItemsFilter);
        }

        public RSObject[] getDoorBlocks() {
            RSObject[] blocks = objects.getAll(blocksFilter);
            return blocks.length == 0 ? null : blocks;
        }

        public RSObject getNearestDoorBlock() {
            return objects.getNearest(blocksFilter);
        }

        public RSObject[] getOpenDoors() {
            RSObject[] doors = objects.getAll(openDoorsFilter);
            return doors.length == 0 ? null : doors;
        }

        public RSObject getNearestOpenDoor() {
            return objects.getNearest(openDoorsFilter);
        }

        public RSObject[] getClosedDoors() {
            RSObject[] doors = objects.getAll(closedDoorsFilter);
            return doors.length == 0 ? null : doors;
        }

        public RSObject getNearestClosedDoor() {
            return objects.getNearest(closedDoorsFilter);
        }

        public RSObject[] getAllObjects() {
            RSObject[] objs = objects.getAll(new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    return area.contains(t.getLocation());
                }
            });
            return objs.length == 0 ? null : objs;
        }

        public Point getCoord() {
            return new Point(x, y);
        }

        @Override
        protected Room clone() {
            return new Room(x, y, neighbours);//, doorLocs, area, parent);
        }

        public void setParent(Room parent) {
            setParent(parent, false);
        }

        public void setParent(Room p, boolean overwritenull) {
            if (overwritenull || parent == null) {
                parent = p;
            }
        }

        public final Room getParent() {
            return parent;
        }

        @Override
        public boolean equals(Object o) {
            if (o instanceof Room) {
                return ((Room) o).x == x && ((Room) o).y == y;
            }
            return false;
        }

        @Override
        public String toString() {
            return "Room [" + x + ";" + y + "]";
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 41 * hash + this.index;
            hash = 41 * hash + this.x;
            hash = 41 * hash + this.y;
            hash = 41 * hash + this.neighbours;
            return hash;
        }
    }

    public Room[] getPath(int x1, int y1, int x2, int y2) {
        return getPath(getRoom(x1, y1), getRoom(x2, y2));
    }

    public Room[] getPath(Room start, Room end) {
        //boolean b = false;
        //PathIdentifier key = null;
        //for (PathIdentifier r : paths.keySet()) {
        //    if (r.end.equals(end)) {
        //        b = true;
        //        key = r;
        //        break;
        //    }
        //}
        //if (b) {
        //    Room[] path = paths.get(key);
        //    for (Room r : path) {
        //        if (r.equals(start)) {
        //            return path;
        //        }
        //    }
        //}
        ArrayList<Room> open = new ArrayList<Room>();
        ArrayList<Room> closed = new ArrayList<Room>();
        open.add(start);
        Timer timer = new Timer(5000);
        while (open.size() > 0 && timer.isRunning()) {
            Room curr = open.get(0);
            open.remove(curr);
            closed.add(curr);
            for (Room room : curr.getNeighbours()) {
                if (!closed.contains(room)) {
                    if (!open.contains(room)) {
                        room.setParent(curr);
                        open.add(room);
                    }
                }
            }
            if (curr.equals(end)) {
                Room[] path = new Room[0];
                do {
                    path = Arrays.copyOf(path, path.length + 1);
                    path[path.length - 1] = curr;
                    curr = curr.getParent();
                    if (curr == null || start == null) {
                        return null;
                    }
                } while (!curr.equals(start));
                path = Arrays.copyOf(path, path.length + 1);
                path[path.length - 1] = start;
                Room[] pathReverse = new Room[path.length];
                for (int i = 0; i < path.length; i++) {
                    pathReverse[i] = path[path.length - i - 1];
                }
                //if (b) {
                //    if (Arrays.asList(path).containsAll(Arrays.asList(key))) {
                //        paths.remove(key);
                //    }
                //}
                //paths.put(new PathIdentifier(start, end), pathReverse);
                //return paths.get(new PathIdentifier(start, end));
                return pathReverse;
            }
        }
        return null;
    }

    public class Timer {

        long startTime;
        long time;

        public Timer(int time) {
            this.time = time;
            this.startTime = System.currentTimeMillis();
        }

        public boolean isRunning() {
            return (System.currentTimeMillis() - startTime) < time;
        }
    }

    public Room[] getPath2(final Room start, final Room finish) {
        log("Finding path between: " + start + " and " + finish);
        boolean b = false;
        PathIdentifier key = null;
        for (PathIdentifier r : paths.keySet()) {
            if (r.end.equals(finish)) {
                b = true;
                key = r;
                break;
            }
        }
        if (b) {
            Room[] path = paths.get(key);
            for (Room r : path) {
                if (r.equals(start)) {
                    log("Returned cached path: " + start + "; " + Arrays.toString(path));
                    return path;
                }
            }
        }
        ArrayList<Room> path = new ArrayList<>();
        ArrayList<Room> open = new ArrayList<>();
        ArrayList<Room> closed = new ArrayList<>();
        try {//Room current = begin;
            open.clear();
            closed.clear();
            path.clear();
            Room begin = start.clone();
            Room end = finish.clone();
            open.add(begin);
            //log(begin.getParent());
            //Thread.sleep(500);
            while (open.size() > 0) {
                ArrayList<Room> openC = (ArrayList<Room>) open.clone();
                for (Room current : openC) {
                    Room lowestdist = null;
                    for (Room s : current.getNeighbours()) {
                        if (!closed.contains(s)) {
                            if (lowestdist == null || Point.distance(s.x, s.y, end.x, end.y) < Point.distance(lowestdist.x, lowestdist.y, end.x, end.y)) {
                                lowestdist = s.clone();
                            }
                        }
                    }
                    if (lowestdist != null && lowestdist.equals(end)) {
                        //lowestdist.setParent(current, true);
                        end.setParent(current, true);
                        open.clear();
                        break;
                    } else {
                        open.remove(current);
                        closed.add(current);
                        for (Room s : current.getNeighbours()) {
                            if (!closed.contains(s) && !open.contains(s)) {
                                open.add(s);
                            }
                        }
                    }
                }
            }
            if (end.getParent() == null) {
                return null;
            }
            Room current = end;
            boolean goodToGo = false;
            path.clear();
            path.add(end);
            while (!goodToGo) {
                if (path.size() > 50) {
                    return null;
                }
                path.add(current.getParent());
                current = current.getParent();
                if (begin.equals(current) || current.getParent() == null) {
                    goodToGo = true;
                }
            }
            Collections.reverse(path);
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (b) {
            if (path.containsAll(Arrays.asList(key))) {
                paths.remove(key);
            }
        }
        paths.put(new PathIdentifier(start, finish), path.toArray(new Room[path.size()]));
        return paths.get(new PathIdentifier(start, finish));
    }

    public class PathIdentifier {

        public Room start;
        public Room end;

        public PathIdentifier(Room start, Room end) {
            this.start = start;
            this.end = end;
        }

        @Override
        public int hashCode() {
            int hash = 7;
            hash = 97 * hash + start.hashCode();
            hash = 97 * hash + end.hashCode();
            return hash;
        }

        public boolean equals(Object o) {
            if (o instanceof PathIdentifier) {
                PathIdentifier pi = (PathIdentifier) o;
                return start.equals(pi.start) && end.equals(pi.end);
            }
            return false;
        }
    }

    public RSArea getAreaContaining(RSTile t, ArrayList<RSArea> areas) {
        for (RSArea a : areas) {
            if (a.contains(t)) {
                return a;
            }
        }
        return null;
    }

    public boolean isFullyOnScreen(RSTile tile) {
        Point p1 = calc.tileToScreen(tile, 0.0, 1.0, 0);
        Point p2 = calc.tileToScreen(tile, 0.0, 0.0, 0);
        Point p3 = calc.tileToScreen(tile, 1.0, 0.0, 0);
        Point p4 = calc.tileToScreen(tile, 1.0, 1.0, 0);
        int c = 0;
        if (calc.pointOnScreen(p1)) {
            c++;
        }
        if (calc.pointOnScreen(p2)) {
            c++;
        }
        if (calc.pointOnScreen(p3)) {
            c++;
        }
        if (calc.pointOnScreen(p4)) {
            c++;
        }
        return c == 4;
    }

    public boolean isDoor(RSObject o) {

        /*
         * DOORS.doors, DOORS.guardian_doors, DOORS.broken_door,
         * DOORS.blue_corner, DOORS.blue_crescent, DOORS.blue_diamond,
         * DOORS.blue_pentagon, DOORS.blue_rectangle, DOORS.blue_shield,
         * DOORS.blue_shield, DOORS.blue_triangle, DOORS.blue_wedge,
         * DOORS.crimson_corner, DOORS.crimson_crescent, DOORS.crimson_diamond,
         * DOORS.crimson_pentagon, DOORS.crimson_rectangle,
         * DOORS.crimson_shield, DOORS.crimson_shield, DOORS.crimson_triangle,
         * DOORS.crimson_wedge, DOORS.gold_corner, DOORS.gold_crescent,
         * DOORS.gold_diamond, DOORS.gold_pentagon, DOORS.gold_rectangle,
         * DOORS.gold_shield, DOORS.gold_shield, DOORS.gold_triangle,
         * DOORS.gold_wedge, DOORS.green_corner, DOORS.green_crescent,
         * DOORS.green_diamond, DOORS.green_pentagon, DOORS.green_rectangle,
         * DOORS.green_shield, DOORS.green_shield, DOORS.green_triangle,
         * DOORS.green_wedge, DOORS.orange_corner, DOORS.orange_crescent,
         * DOORS.orange_diamond, DOORS.orange_pentagon, DOORS.orange_rectangle,
         * DOORS.orange_shield, DOORS.orange_shield, DOORS.orange_triangle,
         * DOORS.orange_wedge, DOORS.purple_corner, DOORS.purple_crescent,
         * DOORS.purple_diamond, DOORS.purple_pentagon, DOORS.purple_rectangle,
         * DOORS.purple_shield, DOORS.purple_shield, DOORS.purple_triangle,
         * DOORS.purple_wedge, DOORS.silver_corner, DOORS.silver_crescent,
         * DOORS.silver_diamond, DOORS.silver_pentagon, DOORS.silver_rectangle,
         * DOORS.silver_shield, DOORS.silver_shield, DOORS.silver_triangle,
         * DOORS.silver_wedge, DOORS.yellow_corner, DOORS.yellow_crescent,
         * DOORS.yellow_diamond, DOORS.yellow_pentagon, DOORS.yellow_rectangle,
         * DOORS.yellow_shield, DOORS.yellow_shield, DOORS.yellow_triangle,
         * DOORS.yellow_wedge
         */
        return isObjectID(o, getAllDoors());
    }

    public boolean isObjectID(RSObject o, ArrayList<Integer> ids) {
        if (o == null) {
            return false;
        }
        int oid = o.getID();
        for (int id : ids) {
            if (oid == id) {
                return true;
            }
        }
        return false;
    }

    public Room getRoom(int x, int y) {
        for (Room r : rooms) {
            if (r.x == x && r.y == y) {
                return r;
            }
        }
        return null;
    }

    public boolean inDungeon() {
        return settings.getSetting(1773) != 0;
    }

    public Room getCurrentRoom() {
        for (Room r : rooms) {
            if (r.area.contains(players.getMyPlayer().getLocation())) {
                return r;
            }
        }
        return null;
    }
    public final int WALL = 0x200000 | 0x40000000;

    public RSArea getAreaAroundObject(RSObject o, Room r) {
        ArrayList<RSTile> areatiles = new ArrayList<RSTile>();
        int z = 0;
        RSTile[] roomTiles = getRoomTiles(o, areatiles, z, r);
        int smallestX = Integer.MAX_VALUE, biggestX = 0, smallestY = Integer.MAX_VALUE, biggestY = 0;
        for (RSTile tile : roomTiles) {
            if (tile.getX() < smallestX) {
                smallestX = tile.getX();
            }
            if (tile.getY() < smallestY) {
                smallestY = tile.getY();
            }
            if (tile.getX() > biggestX) {
                biggestX = tile.getX();
            }
            if (tile.getY() > biggestY) {
                biggestY = tile.getY();
            }
        }
        return new RSArea(smallestX - 1, smallestY - 1, biggestX + 1, biggestY + 1);
    }

    public RSArea getAreaAround(RSTile t) {
        ArrayList<RSTile> areatiles = new ArrayList<RSTile>();
        int z = 0;
        RSTile[] roomTiles = getRoomTiles(t, areatiles, z);
        int smallestX = Integer.MAX_VALUE, biggestX = 0, smallestY = Integer.MAX_VALUE, biggestY = 0;
        for (RSTile tile : roomTiles) {
            if (tile.getX() < smallestX) {
                smallestX = tile.getX();
            }
            if (tile.getY() < smallestY) {
                smallestY = tile.getY();
            }
            if (tile.getX() > biggestX) {
                biggestX = tile.getX();
            }
            if (tile.getY() > biggestY) {
                biggestY = tile.getY();
            }
        }
        return new RSArea(smallestX - 1, smallestY - 1, biggestX + 1, biggestY + 1);
    }

    public RSTile[] fill(RSTile location, ArrayList<RSTile> areatiles2, int z) {
        RSTile[] areatiles = getRoomTiles(location, areatiles2, z);
        for (RSTile tile : areatiles) {
            RSTile[] checkTiles = getSurroundingTiles(tile, true);
            for (RSTile checkTile : checkTiles) {
                if (!areatiles2.contains(checkTile)) {
                    areatiles2.add(checkTile);
                }
            }
        }
        RSTile[] returnTiles = new RSTile[areatiles2.size()];
        for (int i = 0; i < areatiles2.size(); i++) {
            returnTiles[i] = areatiles2.get(i);
        }
        return returnTiles;
    }

    private RSTile[] getRoomTiles(RSTile location, ArrayList<RSTile> areatiles, int z) {
        z++;
        if ((getCollisionFlagAtTile(location) & WALL) != 0) {
            RSTile[] tempTiles = new RSTile[areatiles.size()];
            for (int i = 0; i < areatiles.size(); i++) {
                tempTiles[i] = areatiles.get(i);
            }
            return tempTiles;
        }
        RSTile[] checkTiles = getSurroundingTiles(location, true);
        int[] flagTiles = getSurroundingCollisionFlags(location, true);
        for (int i = 0; i < checkTiles.length; i++) {
            if ((flagTiles[i] & WALL) == 0 && notDoor(checkTiles[i]) && z <= 1100) {
                if (!areatiles.contains(checkTiles[i])) {
                    areatiles.add(checkTiles[i]);
                    getRoomTiles(checkTiles[i], areatiles, z);
                }
            }
        }
        RSTile[] tempTiles = new RSTile[areatiles.size()];
        for (int i = 0; i < areatiles.size(); i++) {
            tempTiles[i] = areatiles.get(i);
        }
        return tempTiles;
    }

    private RSTile[] getRoomTiles(RSObject o, ArrayList<RSTile> areatiles, int z, Room r) {
        if (!r.area.contains(o.getLocation())) {
            return null;
        }
        z++;
        RSTile[] checkTiles = getSurroundingTiles(o.getLocation(), true);
        for (RSTile checkTile : checkTiles) {
            RSObject[] objs = objects.getAllAt(checkTile);
            if (objs != null) {
                for (RSObject obj : objs) {
                    if (obj.getID() == o.getID()) {
                        if (!areatiles.contains(checkTile) && z < 100) {
                            areatiles.add(checkTile);
                            getRoomTiles(obj, areatiles, z, r);
                            break;
                        }
                    }
                }
            }
        }
        return areatiles.toArray(new RSTile[areatiles.size()]);
    }

    public boolean notDoor(RSTile t) {
        ArrayList<Integer> doorIDs = getAllDoors();
        RSObject[] o = objects.getAllAt(t);
        if (o != null) {
            for (RSObject ob : o) {
                if (doorIDs.contains(ob.getID())) {
                    return false;
                }
            }
        }
        return true;
    }

    public int getCollisionFlagAtTile(RSTile tile) {
        int[][] flags = walking.getCollisionFlags(game.getPlane());
        int x = tile.getX();
        int y = tile.getY();
        int xOff = x - game.getBaseX() - walking.getCollisionFlagsOffset(game.getPlane()).getX();
        int yOff = y - game.getBaseY() - walking.getCollisionFlagsOffset(game.getPlane()).getY();
        return flags[xOff][yOff];
    }

    public RSTile[] getSurroundingTiles(RSTile tile) {
        return getSurroundingTiles(tile, false);
    }

    public RSTile[] getSurroundingTiles(RSTile tile, boolean eightTiles) {
        int x = tile.getX();
        int y = tile.getY();
        RSTile north = new RSTile(x, y + 1);
        RSTile east = new RSTile(x + 1, y);
        RSTile south = new RSTile(x, y - 1);
        RSTile west = new RSTile(x - 1, y);
        RSTile northEast;
        RSTile southEast;
        RSTile southWest;
        RSTile northWest;
        if (eightTiles) {
            northEast = new RSTile(x + 1, y + 1);
            southEast = new RSTile(x + 1, y - 1);
            southWest = new RSTile(x - 1, y - 1);
            northWest = new RSTile(x - 1, y + 1);
            return new RSTile[]{north, northEast, east, southEast, south, southWest, west, northWest};
        }
        return new RSTile[]{north, east, south, west};
    }

    public int[] getSurroundingCollisionFlags(RSTile tile) {
        return getSurroundingCollisionFlags(tile, false);
    }

    public int[] getSurroundingCollisionFlags(RSTile tile, boolean eightTiles) {
        int[][] flags = walking.getCollisionFlags(game.getPlane());
        int x = tile.getX();
        int y = tile.getY();
        RSTile cfo = walking.getCollisionFlagsOffset(game.getPlane());
        int xOff = x - game.getBaseX() - cfo.getX();
        int yOff = y - game.getBaseY() - cfo.getY();
        int fNorth = flags[xOff][yOff + 1];
        int fEast = flags[xOff + 1][yOff];
        int fSouth = flags[xOff][yOff - 1];
        int fWest = flags[xOff - 1][yOff];
        int fNorthEast;
        int fSouthEast;
        int fSouthWest;
        int fNorthWest;
        if (eightTiles) {
            fNorthEast = flags[xOff + 1][yOff + 1];
            fSouthEast = flags[xOff + 1][yOff - 1];
            fSouthWest = flags[xOff - 1][yOff - 1];
            fNorthWest = flags[xOff - 1][yOff + 1];
            return new int[]{fNorth, fNorthEast, fEast, fSouthEast, fSouth, fSouthWest, fWest, fNorthWest};
        }
        return new int[]{fNorth, fEast, fSouth, fWest};
    }

    public void drawTileOnScreen(Graphics g, RSTile t, Color c) {
        if (t == null) {
            return;
        }
        final Point I = calc.tileToScreen(new RSTile(t.getX(), t.getY()), 0, 0, 0);
        final Point II = calc.tileToScreen(new RSTile(t.getX() + 1, t.getY()), 0, 0, 0);
        final Point III = calc.tileToScreen(new RSTile(t.getX(), t.getY() + 1), 0, 0, 0);
        final Point IV = calc.tileToScreen(new RSTile(t.getX() + 1, t.getY() + 1), 0, 0, 0);
        if (I.x != -1 && II.x != -1 && III.x != -1 && IV.x != -1 && I.y != -1 && II.y != -1 && III.y != -1 && IV.y != -1) {
            getMyPlayer().getHeight();
            g.setColor(c);
            g.fillPolygon(new int[]{III.x, IV.x, II.x, I.x}, new int[]{III.y, IV.y, II.y, I.y}, 4);
        }
    }

    @Override
    public void onRepaint(Graphics g) {
        if (!game.isLoggedIn()) {
            return;
        }
        int xC = 50;
        int yC = 50;
        if (interfaces.get(137).getComponent(55).getText().contains("paint")) {
            Room r = getCurrentRoom();
            if (r != null) {
                if (interfaces.get(137).getComponent(55).getText().contains("tiles")) {
                    for (int i = 0; i < r.getTiles().length; i++) {
                        for (int j = 0; j < r.getTiles()[i].length; j++) {
                            RSTile t = r.getTiles()[i][j];
                            if (t == null) {
                                continue;
                            }
                            if (calc.tileOnScreen(t)) {
                                String value = Integer.toString(i);
                                Point p = calc.tileToScreen(t, 0.5, 0.5, 0);
                                FontMetrics metrics = g.getFontMetrics(g.getFont());
                                int width = metrics.stringWidth(value);
                                g.setColor(Color.blue);
                                g.drawString(value, p.x - (width / 2), p.y + 15);
                                g.fillRect(p.x - 1, p.y - 1, 3, 3);
                                drawTileOnScreen(g, t, new Color(255, 0, 0, 100));
                            }
                            g.setColor(new Color(255, 0, 0, 75));
                            drawTileOnMinimap(g, t, playerX, playerY);
                        }
                    }
                    drawTileOnScreen(g, r.getDoorTile(Wall.NORTH), new Color(255, 0, 0));
                    drawTileOnScreen(g, r.getDoorTile(Wall.SOUTH), new Color(255, 255, 0));
                    drawTileOnScreen(g, r.getDoorTile(Wall.WEST), new Color(255, 255, 255));
                    drawTileOnScreen(g, r.getDoorTile(Wall.EAST), new Color(0, 255, 255));
                }
                g.setColor(Color.green);
                g.drawString("Neighbours: ", xC, yC += 12);
                if (r.gotNeighbour(Wall.NORTH)) {
                    g.drawString("NORTH", xC + 15, yC += 12);
                }
                if (r.gotNeighbour(Wall.WEST)) {
                    g.drawString("WEST", xC + 15, yC += 12);
                }
                if (r.gotNeighbour(Wall.EAST)) {
                    g.drawString("EAST", xC + 15, yC += 12);
                }
                if (r.gotNeighbour(Wall.SOUTH)) {
                    g.drawString("SOUTH", xC + 15, yC += 12);
                }
                xC = 50;
                yC = 120;
                g.setColor(Color.green);
                g.drawString("Monsters in room: ", xC, yC += 12);
                RSNPC[] monsters = r.getMonsters();
                if (monsters != null) {
                    for (RSNPC monster : monsters) {
                        g.setColor(Color.yellow);
                        drawTileOnMinimap(g, monster.getLocation(), playerX, playerY);
                        drawTileOnScreen(g, monster.getLocation(), new Color(Color.yellow.getRed(), Color.yellow.getGreen(), Color.yellow.getBlue(), 100));
                        String name = (monster.getName() == null) ? "Unknown" : monster.getName();
                        String id = (String) ((monster.getID() == -1) ? "" : ("; ID: " + monster.getID()));
                        String level = (String) ((monster.getLevel() == -1) ? "" : ("; Level: " + monster.getLevel()));
                        String panimation = (String) ((monster.getPassiveAnimation() == -1) ? "" : ("; Passive anim: " + monster.getPassiveAnimation()));
                        String animation = (String) ((monster.getAnimation() == -1) ? "" : ("; Animation: " + monster.getAnimation()));
                        String hp = (String) ((monster.getHPPercent() == -1) ? "" : ("; HP: " + monster.getHPPercent()));
                        g.setColor(Color.green);
                        g.drawString(name + id + level + hp + panimation + animation, xC + 15, yC += 12);
                    }
                }
                xC = 170;
                yC = 120;
                g.setColor(Color.green);
                g.drawString("Current room: " + r.x + "; " + r.y, xC, yC += 12);
            }
            final ArrayList<Integer> keyIDs = getAllKeys();
            final ArrayList<Integer> doorIDs = getAllDoors();
            final ArrayList<Integer> blockIDs = getAllBlocks();
            if (game.getCurrentTab() == Game.TAB_INVENTORY) {
                for (RSItem i : inventory.getItems()) {
                    for (int id : keyIDs) {
                        if (i.getID() == id) {
                            RSComponent rsc = i.getComponent();
                            int x = rsc.getAbsoluteX();
                            int y = rsc.getAbsoluteY();
                            int w = rsc.getWidth();
                            int h = rsc.getHeight();
                            g.setColor(getColorByName(i.getName(), new Color(255, 225, 0)));
                            g.drawRect(x, y, w, h);
                        }
                    }
                }
            }
            RSGroundItem[] items = groundItems.getAll(new Filter<RSGroundItem>() {

                @Override
                public boolean accept(RSGroundItem t) {
                    return keyIDs.contains(t.getItem().getID());
                }
            });
            xC = 170;
            yC = 50;
            g.setColor(Color.green);
            g.drawString("Keys in dungeon: ", xC, yC += 12);
            for (RSGroundItem item : items) {
                String name = getKeyName(item.getItem().getID()).replace("_", " ").trim();
                name = name.substring(0, 1).toUpperCase() + name.substring(1);
                g.setColor(getColorByName(name, Color.green));
                drawTileOnMinimap(g, item.getLocation(), playerX, playerY);
                drawTileOnScreen(g, item.getLocation(), g.getColor());
                g.drawString(name, xC + 15, yC += 12);
            }
            g.setColor(Color.green);
            RSObject[] objs = objects.getAll(new Filter<RSObject>() {

                @Override
                public boolean accept(RSObject t) {
                    return blockIDs.contains(t.getID()) || doorIDs.contains(t.getID());
                }
            });
            if (objs != null) {
                for (RSObject obj : objs) {
                    if (obj == null || obj.getModel() == null || obj.getModel().getTriangles() == null) {
                        continue;
                    }
                    if (doorIDs.contains(obj.getID())) {
                        g.setColor(new Color(255, 0, 0, 100));
                    } else if (blockIDs.contains(obj.getID())) {
                        g.setColor(new Color(255, 255, 255, 100));
                    }
                    Polygon[] triangles = obj.getModel().getTriangles();
                    for (Polygon triangle : triangles) {
                        if (triangle == null) {
                            continue;
                        }
                        g.fillPolygon(triangle);
                    }
                }
            }
        }
        xC = 15;
        yC = 313;
        g.setColor(Color.green);
        g.drawString("State: " + state, xC, yC += 12);
        //int[] xCoords = new int[40];
        //int[] yCoords = new int[40];
        for (int i = -1000; i < 1000; i += 200) {
            g.setColor(new Color(255, 0, 0));
            //if (!xlocs.containsKey(i)) {
            //    xlocs.put(i, random(-2.0, 2.0));
            //    ylocs.put(i, random(-2.0, 2.0));
            //}
            Point p = calc.tileToScreen(players.getMyPlayer().getLocation(), 0.5, 0.5, i);
            //xCoords[i + 20] = p.x;
            //yCoords[i + 20] = p.y;

            if (i == 0) {
                g.fillRect(p.x - 2, p.y - 2, 5, 5);
            } else {
                g.fillRect(p.x, p.y, 1, 1);
            }
            g.drawString(Integer.toString(i), p.x + 5, p.y + 5);
        }
        //g.fillPolygon(xCoords, yCoords, yCoords.length);
    }
    HashMap<Integer, Double> xlocs = new HashMap<Integer, Double>();
    HashMap<Integer, Double> ylocs = new HashMap<Integer, Double>();

    public Color getColorByName(String s, Color defa) {
        if (s == null) {
            return Color.green;
        }
        s = s.toLowerCase().trim();
        if (s.contains("blue")) {
            return Color.cyan;
        } else if (s.contains("crimson")) {
            return Color.red;
        } else if (s.contains("gold")) {
            return Color.yellow;
        } else if (s.contains("green")) {
            return Color.green;
        } else if (s.contains("orange")) {
            return Color.orange;
        } else if (s.contains("purple")) {
            return Color.magenta;
        } else if (s.contains("silver")) {
            return new Color(220, 220, 220);
        } else if (s.contains("yellow")) {
            return Color.yellow;
        }
        return defa;
    }

    public Client getClient() {
        Client c = null;
        Class<?> MethodsProvider = calc.ALLATORI_DEMO.getClass();


        for (Field f : MethodsProvider.getDeclaredFields()) {
            if (f.getType().equals(Client.class)) {

                try {
                    c = (Client) f.get(calc.ALLATORI_DEMO);
                    break;
                } catch (Exception ex) {
                }
            }
        }
        return c;
    }

    private void drawTileOnMinimap(Graphics g, RSTile t, float playerX, float playerY) {
        Point swPoint = toMinimap(t, 0.0, 0.0, playerX, playerY);
        Point nwPoint = toMinimap(t, 1.0, 0.0, playerX, playerY);
        Point nePoint = toMinimap(t, 1.0, 1.0, playerX, playerY);
        Point sePoint = toMinimap(t, 0.0, 1.0, playerX, playerY);
        //if (swPoint.x != -1 && nwPoint.x != -1 && nePoint.x != -1 && sePoint.x != -1 && swPoint.y != -1 && nwPoint.y != -1 && nePoint.y != -1 && sePoint.y != -1) {
        Polygon p = new Polygon(new int[]{swPoint.x, nwPoint.x, nePoint.x, sePoint.x}, new int[]{swPoint.y, nwPoint.y, nePoint.y, sePoint.y}, 4);
        g.fillPolygon(p);
        //}
    }

    public Point toMinimap(RSTile t, double dx, double dy, float playerX, float playerY) {
        double minimapAngle = -1 * Math.toRadians(camera.getAngle());
        int x = (int) (((t.getX() + dx) - playerX) * 4 - 2);
        int y = (int) ((playerY - (t.getY() + dy)) * 4 - 2);
        return new Point((int) Math.round(x * Math.cos(minimapAngle) + y * Math.sin(minimapAngle) + 628),
                (int) Math.round(y * Math.cos(minimapAngle) - x * Math.sin(minimapAngle) + 87));
    }

    @Override
    public void messageReceived(MessageEvent me) {
        String msg = me.getMessage().toLowerCase();
        int id = me.getID();
        if (id == 0) {
            if (msg.contains("welcome to daemonheim")) {
                overallIndex = 0;
                prevRoom = null;
                rooms.clear();
                paths.clear();
                badTiles.clear();
            }
            if ((msg.contains("you need a") && msg.contains("level of") && msg.contains("to do that")) || msg.contains("you are unable")) {
                badTiles.add(players.getMyPlayer().getLocation());
            }
        }
        if (msg.contains("roomsdebug")) {
            for (Room r : rooms) {
                log("d.rooms.add(d.new Room(" + r.x + ", " + r.y + ", " + r.neighbours + "));");
            }
        }

    }

    public static void main(String[] args) {
        Dungeoneer d = new Dungeoneer();
        /*
         * d.rooms.add(d.new Room(0, 0, Wall.EAST)); d.rooms.add(d.new Room(1,
         * 0, Wall.WEST | Wall.NORTH | Wall.SOUTH)); d.rooms.add(d.new Room(1,
         * -1, Wall.EAST | Wall.NORTH | Wall.WEST)); d.rooms.add(d.new Room(2,
         * -1, Wall.EAST | Wall.NORTH | Wall.WEST)); d.rooms.add(d.new Room(2,
         * 0, Wall.EAST | Wall.SOUTH)); d.rooms.add(d.new Room(3, 0, Wall.WEST |
         * Wall.NORTH)); d.rooms.add(d.new Room(3, 1, Wall.SOUTH));
         * d.rooms.add(d.new Room(3, -1, Wall.WEST)); d.rooms.add(d.new Room(0,
         * -1, Wall.WEST | Wall.EAST)); d.rooms.add(d.new Room(-1, -1, Wall.WEST
         * | Wall.EAST)); d.rooms.add(d.new Room(-2, -1, Wall.EAST));
         * d.rooms.add(d.new Room(1, 1, Wall.SOUTH | Wall.WEST | Wall.EAST));
         * d.rooms.add(d.new Room(2, 1, Wall.WEST)); d.rooms.add(d.new Room(0,
         * 1, Wall.WEST | Wall.EAST)); d.rooms.add(d.new Room(-1, 1, Wall.SOUTH
         * | Wall.EAST)); d.rooms.add(d.new Room(-1, 0, Wall.NORTH |
         * Wall.WEST)); d.rooms.add(d.new Room(-2, 0, Wall.NORTH | Wall.EAST));
         * d.rooms.add(d.new Room(-2, 1, Wall.SOUTH));
         */
        /*
         * d.rooms.add(d.new Room(0, 0, 8)); d.rooms.add(d.new Room(-1, 0, 15));
         * d.rooms.add(d.new Room(-1, -1, 3)); d.rooms.add(d.new Room(-1, -2,
         * 1)); d.rooms.add(d.new Room(-2, 0, 12)); d.rooms.add(d.new Room(-3,
         * 0, 7)); d.rooms.add(d.new Room(-3, 1, 6)); d.rooms.add(d.new Room(-2,
         * 1, 8)); d.rooms.add(d.new Room(-3, -1, 5)); d.rooms.add(d.new
         * Room(-2, -1, 8));
         */
        //d.rooms.add(d.new Room(0, 0, 3));
        //d.rooms.add(d.new Room(0, -1, 5));
        //d.rooms.add(d.new Room(1, -1, 12));
        //d.rooms.add(d.new Room(0, 1, 2));
        d.rooms.add(d.new Room(0, 0, 3));
        d.rooms.add(d.new Room(0, -1, 11));
        d.rooms.add(d.new Room(-1, -1, 12));
        d.rooms.add(d.new Room(0, 1, 10));
        d.rooms.add(d.new Room(-1, 1, 4));

        Room[] path = d.getPath(-1, 1, -1, -1);
        for (Room r : path) {
            System.out.println(r.toString());
        }
    }

    public class LocationGetter extends Thread implements Runnable {

        @Override
        public void run() {
            while (isActive()) {
                if (game.isLoggedIn()) {
                    playerX = game.getBaseX() + (((InteractableManager) ((interactable_manager) getClient().getLocalPlayer()).interactable_manager()).getData().getLocation().getX() / 512.0F);
                    playerY = game.getBaseY() + (((InteractableManager) ((interactable_manager) getClient().getLocalPlayer()).interactable_manager()).getData().getLocation().getY() / 512.0F);
                    try {
                        sleep(50);
                    } catch (Exception e) {
                    }
                } else {
                    try {
                        sleep(2000);
                    } catch (Exception e) {
                    }
                }
            }
        }
    }
}
